"""
Key handling utilities for DSA keys, domain parameters and signatures..
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from asn1crypto.algos import DSASignature
from asn1crypto.core import Integer
from asn1crypto.keys import DSAParams

from pkcs11.constants import Attribute
from pkcs11.util import biginteger

if TYPE_CHECKING:
    from pkcs11.types import DomainParameters, PublicKey


def decode_dsa_domain_parameters(der: bytes) -> dict[Attribute, Any]:
    """
    Decode RFC 3279 DER-encoded Dss-Params.

    :param bytes der: DER-encoded parameters
    :rtype: dict(Attribute,*)
    """

    params = DSAParams.load(der)

    return {
        Attribute.BASE: biginteger(params["g"]),
        Attribute.PRIME: biginteger(params["p"]),
        Attribute.SUBPRIME: biginteger(params["q"]),
    }


def encode_dsa_domain_parameters(obj: DomainParameters) -> bytes:
    """
    Encode RFC 3279 DER-encoded Dss-Params.

    :param DomainParameters obj: domain parameters
    :rtype: bytes
    """
    asn1 = DSAParams(
        {
            "g": int.from_bytes(obj[Attribute.BASE], byteorder="big"),
            "p": int.from_bytes(obj[Attribute.PRIME], byteorder="big"),
            "q": int.from_bytes(obj[Attribute.SUBPRIME], byteorder="big"),
        }
    )

    return asn1.dump()


def encode_dsa_public_key(key: PublicKey) -> bytes:
    """
    Encode DSA public key into RFC 3279 DER-encoded format.

    :param PublicKey key: public key
    :rtype: bytes
    """

    asn1 = Integer(int.from_bytes(key[Attribute.VALUE], byteorder="big"))

    return asn1.dump()


def decode_dsa_public_key(der: bytes) -> bytes:
    """
    Decode a DSA public key from RFC 3279 DER-encoded format.

    Returns a `biginteger` encoded as bytes.

    :param bytes der: DER-encoded public key
    :rtype: bytes
    """

    asn1 = Integer.load(der)

    return biginteger(asn1)


def encode_dsa_signature(signature: bytes) -> bytes:
    """
    Encode a signature (generated by :meth:`pkcs11.SignMixin.sign`) into
    DER-encoded ASN.1 (Dss_Sig_Value) format.

    :param bytes signature: signature as bytes
    :rtype: bytes
    """

    asn1 = DSASignature.from_p1363(signature)

    return asn1.dump()


def decode_dsa_signature(der: bytes) -> bytes:
    """
    Decode a DER-encoded ASN.1 (Dss_Sig_Value) signature (as generated by
    OpenSSL/X.509) into PKCS #11 format.

    :param bytes der: DER-encoded signature
    :rtype bytes:
    """

    asn1 = DSASignature.load(der)

    return asn1.to_p1363()
