"""
Local Signature Verifier

Verifies Ed25519 signature over the content digest.
"""

from __future__ import annotations

import base64
import logging
import os
from dataclasses import dataclass
from typing import TYPE_CHECKING, Dict, Optional

from receipts.verifiers.verdict import ProofVerdict

if TYPE_CHECKING:
    from receipts.models_v1 import ReceiptV1

logger = logging.getLogger(__name__)


@dataclass
class SigningKeyConfig:
    """Configuration for verifying signatures."""
    public_keys: Dict[str, bytes]  # kid -> public key bytes


def _load_public_keys() -> Dict[str, bytes]:
    """
    Load public keys from environment or config.

    Supports LOOM_ED25519_PUBLIC_KEY_B64 for single key,
    or LOOM_ED25519_PUBLIC_KEYS_JSON for multiple.
    """
    keys = {}

    # Single key from env
    single_key = os.environ.get("LOOM_ED25519_PUBLIC_KEY_B64")
    if single_key:
        try:
            key_bytes = base64.b64decode(single_key)
            kid = os.environ.get("LOOM_SIGNING_KEY_ID", "default")
            keys[kid] = key_bytes
        except Exception as e:
            logger.warning(f"Failed to load public key: {e}")

    # Multiple keys from JSON env var (future)
    # keys_json = os.environ.get("LOOM_ED25519_PUBLIC_KEYS_JSON")
    # if keys_json:
    #     import json
    #     for kid, b64 in json.loads(keys_json).items():
    #         keys[kid] = base64.b64decode(b64)

    return keys


def verify_local_signature(
    receipt: "ReceiptV1",
    config: Optional[SigningKeyConfig] = None,
) -> ProofVerdict:
    """
    Verify the local-signature proof.

    Checks that the Ed25519 signature over the content digest is valid
    for the claimed key ID.

    Args:
        receipt: The ReceiptV1 to verify
        config: Optional key configuration (loads from env if not provided)

    Returns:
        ProofVerdict with ok/fail/skipped status
    """
    from receipts.models_v1 import LocalSignatureProof, ContentDigestProof

    # Get the local-signature proof
    proof = receipt.get_proof("local-signature")
    if proof is None:
        return ProofVerdict.fail(
            kind="local-signature",
            reason="No local-signature proof present",
        )

    if not isinstance(proof, LocalSignatureProof):
        return ProofVerdict.fail(
            kind="local-signature",
            reason=f"Invalid proof type: {type(proof).__name__}",
        )

    # Get the content digest to verify against
    digest_proof = receipt.get_proof("content-digest")
    if digest_proof is None or not isinstance(digest_proof, ContentDigestProof):
        return ProofVerdict.fail(
            kind="local-signature",
            reason="No content-digest proof to verify signature against",
        )

    # Load keys
    if config is None:
        keys = _load_public_keys()
        if not keys:
            return ProofVerdict.skipped(
                kind="local-signature",
                reason="No public keys configured (set LOOM_ED25519_PUBLIC_KEY_B64)",
            )
        config = SigningKeyConfig(public_keys=keys)

    # Get the key for this signature
    if proof.kid not in config.public_keys:
        return ProofVerdict.fail(
            kind="local-signature",
            reason=f"Unknown key ID: {proof.kid}",
            details={"known_kids": list(config.public_keys.keys())},
        )

    public_key = config.public_keys[proof.kid]

    # Decode signature and digest
    try:
        sig_bytes = base64.b64decode(proof.sig)
        digest_bytes = base64.b64decode(digest_proof.value)
    except Exception as e:
        return ProofVerdict.fail(
            kind="local-signature",
            reason=f"Failed to decode signature or digest: {e}",
        )

    # Verify with nacl
    try:
        from nacl.signing import VerifyKey
        from nacl.exceptions import BadSignature

        verify_key = VerifyKey(public_key)
        verify_key.verify(digest_bytes, sig_bytes)
    except BadSignature:
        return ProofVerdict.fail(
            kind="local-signature",
            reason="Signature verification failed",
            details={"kid": proof.kid},
        )
    except ImportError:
        return ProofVerdict.skipped(
            kind="local-signature",
            reason="nacl not available for signature verification",
        )
    except Exception as e:
        return ProofVerdict.fail(
            kind="local-signature",
            reason=f"Signature verification error: {e}",
        )

    return ProofVerdict.ok(
        kind="local-signature",
        reason=f"Signature verified (kid={proof.kid})",
    )
