from __future__ import annotations

import enum
from typing import FrozenSet, List, Mapping, NamedTuple, Optional, Union
from typing_extensions import TypeAlias


__all__ = [
    "Bundle",
    "IdentityKeyFormat",
    "Header",
    "JSONType",
    "JSONObject",
    "SecretType"
]


################
# Type Aliases #
################

JSONType: TypeAlias = Union[Mapping[str, "JSONType"], List["JSONType"], str, int, float, bool, None]
JSONObject: TypeAlias = Mapping[str, "JSONType"]


############################
# Structures (NamedTuples) #
############################

class Bundle(NamedTuple):
    """
    The bundle is a collection of public keys and signatures used by the X3DH protocol to achieve asynchronous
    key agreements while providing forward secrecy and cryptographic deniability. Parties that want to be
    available for X3DH key agreements have to publish their bundle somehow. Other parties can then use that
    bundle to perform a key agreement.
    """

    identity_key: bytes
    signed_pre_key: bytes
    signed_pre_key_sig: bytes
    pre_keys: FrozenSet[bytes]


class Header(NamedTuple):
    """
    The header generated by the active party as part of the key agreement, and consumed by the passive party
    to derive the same shared secret.
    """

    identity_key: bytes
    ephemeral_key: bytes
    signed_pre_key: bytes
    pre_key: Optional[bytes]


################
# Enumerations #
################

@enum.unique
class IdentityKeyFormat(enum.Enum):
    """
    The two supported public key formats for the identity key:

    * Curve25519 public keys: 32 bytes, the little-endian encoding of the u coordinate as per `RFC 7748,
      section 5 "The X25519 and X448 Functions" <https://www.rfc-editor.org/rfc/rfc7748.html#section-5>`_.
    * Ed25519 public keys: 32 bytes, the little-endian encoding of the y coordinate with the sign bit of the x
      coordinate stored in the most significant bit as per `RFC 8032, section 3.2 "Keys"
      <https://www.rfc-editor.org/rfc/rfc8032.html#section-3.2>`_.
    """

    CURVE_25519 = "CURVE_25519"
    ED_25519 = "ED_25519"


@enum.unique
class SecretType(enum.Enum):
    """
    The two types of secrets that an :class:`~x3dh.identity_key_pair.IdentityKeyPair` can use internally: a
    seed or a private key.
    """

    SEED = "SEED"
    PRIV = "PRIV"
