from typing import Mapping


def signature(signages):
    """
    Creates  Signature HTTP header item from signages list

    RFC8941 Structured Field Values for HTTP

    Returns:
        header (dict): {'Signature': 'value'} where value is RFC8941 compliant
        (Structured Field Values for HTTP) formatted str of of Signage group.
        Each signage group is separated by a comma. Each group is parameter list
        of label=value items separated by ;
        The signer and indexed are special parameters in each group.
        This format is compatible with HTTP servers that merge multiple signature
        headers into one header by iteratively appending the comma separated
        value from each Signature header.

    Parameters:
        signages (list): items are Signage namedtuples,
                           (markers, indexed, signer, ordinal, kind)
            where:
                markers (Union[list, dict]): When dict each item (key, val) has
                    key as str identifier of marker and has val as instance of
                    either coring.Siger or coring.Cigar.
                    When list each item is instance of either coring.Siger or
                    coring.Cigar.
                    All markers must be of same class
                indexed (bool): True means marker values are indexed signatures
                    using coring.Siger. False means marker values are unindexed
                    signatures using coring.Cigar. None means auto detect from
                    first marker value class. All markers must be of same class.
                signer (str): optional identifier of signage. May be a
                    multi-sig group identifier. Default is None. When None or
                    empty signer is not included in header value
                ordinal (str): optional ordinal hex str of int that is an ordinal
                               such as sequence number to further identify the
                               keys used for the signatures. Usually when indexed
                               with signer and digest
                digest (str): optional CESR Base64 serialization of a digest to
                              further identify the keys used for the signatures.
                              Usually when indexed with signer and ordinal
                kind (str): serialization kind of the markers and other primitives


    """
    values = []  # list of parameter items value str for each signage
    for signage in signages:
        markers = signage.markers
        indexed = signage.indexed
        signer = signage.signer
        ordinal = signage.ordinal
        digest = signage.digest
        kind = signage.kind

        if isinstance(markers, Mapping):
            tags = list(markers.keys())
            markers = list(markers.values())
        else:
            tags = []

        if indexed is None:
            indexed = hasattr(markers[0], "index")

        items = []
        tag = 'indexed'
        val = '?1' if indexed else '?0'  #  RFC8941 HTTP structured field values
        items.append(f'{tag}="{val}"')
        if signer:
            tag = "signer"
            val = signer
            items.append(f'{tag}="{val}"')
        if ordinal:
            tag = "ordinal"
            val = ordinal
            items.append(f'{tag}="{val}"')
        if digest:
            tag = "digest"
            val = digest
            items.append(f'{tag}="{val}"')
        if kind:
            tag = "kind"
            val = kind
            items.append(f'{tag}="{val}"')

        for i, marker in enumerate(markers):
            if tags:
                tag = tags[i]
            else:  # assign defaults names since not provided
                if hasattr(marker, "index"):  # Siger has index
                    if not indexed:
                        raise ValueError(f"Indexed signature marker {marker} when "
                                         f"indexed False.")
                    tag = str(marker.index)
                elif hasattr(marker, "verfer"):  # Cigar has verfer but not index
                    if indexed:
                        raise ValueError(f"Unindexed signature marker {marker}"
                                         f"  when indexed True.")
                    tag = marker.verfer.qb64
                else:
                    raise ValueError(f"Invalid signature marker instance = "
                                     f"{marker}.")

            val = marker.qb64
            items.append(f'{tag}="{val}"')

        values.append(";".join(items))

    return dict(Signature=",".join(values))