"""MailioReceipt v1 - Cryptographically verifiable event records."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Literal

from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

if TYPE_CHECKING:
    from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey

from mailio_receipt.canonicalize import canonicalize, compute_digest
from mailio_receipt.did_resolver import DIDWebResolver
from mailio_receipt.errors import (
    BindingMismatchError,
    ChainError,
    ChainIntegrityError,
    DIDNetworkError,
    DIDNotFoundError,
    DIDResolutionError,
    ExecutionBlockedError,
    ExpiredApprovalError,
    InvalidSignatureError,
    MailioReceiptError,
    MissingPredecessorError,
    RevocationError,
    SignatureError,
    SignerNotFoundError,
    ValidationError,
)
from mailio_receipt.execution import (
    BlockingReason,
    ExecutionDecision,
    check_execution,
)
from mailio_receipt.models import (
    Actors,
    ArtifactBinding,
    Binding,
    Chain,
    Intent,
    IntentKind,
    MailioAuditEvent,
    MailioReceipt,
    MessageBinding,
    Signature,
    SignedMetadata,
    create_event,
)
from mailio_receipt.signing import create_jws_detached
from mailio_receipt.types import DIDResolver
from mailio_receipt.verification import (
    ChainVerificationResult,
    SignerInfo,
    VerificationResult,
    verify_chain,
    verify_receipt,
)

__version__ = "0.0.4"

__all__ = [
    # Version
    "__version__",
    # Creation
    "create_receipt",
    "create_event",
    "compute_chain_digest",
    "chain_from",
    # Models
    "MailioReceipt",
    "MailioAuditEvent",
    "Actors",
    "Intent",
    "IntentKind",
    "Chain",
    "Binding",
    "ArtifactBinding",
    "MessageBinding",
    "Signature",
    "SignedMetadata",
    # DID Resolution
    "DIDResolver",
    "DIDWebResolver",
    # Verification
    "verify_receipt",
    "verify_chain",
    "VerificationResult",
    "ChainVerificationResult",
    "SignerInfo",
    # Errors
    "MailioReceiptError",
    "ValidationError",
    "SignatureError",
    "InvalidSignatureError",
    "SignerNotFoundError",
    "ChainError",
    "ChainIntegrityError",
    "MissingPredecessorError",
    "DIDResolutionError",
    "DIDNotFoundError",
    "DIDNetworkError",
    "ExecutionBlockedError",
    "RevocationError",
    "ExpiredApprovalError",
    "BindingMismatchError",
    # Execution
    "check_execution",
    "ExecutionDecision",
    "BlockingReason",
]


def create_receipt(
    *,
    event: MailioAuditEvent,
    private_key: EllipticCurvePrivateKey | Ed25519PrivateKey,
    signer_did: str,
    role: Literal["user", "agent", "authority"] = "agent",
) -> MailioReceipt:
    """
    Create a signed receipt for an event.

    Args:
        event: The event to receipt (must be fully populated)
        private_key: EC P-256 or Ed25519 private key for signing
        signer_did: DID of the signer (must match key in DID document)
        role: Role of the signer in this event

    Returns:
        MailioReceipt with computed digest and signature

    Raises:
        ValidationError: If event is invalid
        SignatureError: If signing fails
    """
    # Compute event digest
    event_dict = event.to_dict()
    event_digest = compute_digest(event_dict)

    # Canonicalize event for signing
    canonical_event = canonicalize(event_dict)

    # Create JWS signature
    try:
        jws = create_jws_detached(canonical_event, private_key, signer_did)
    except Exception as e:
        raise SignatureError(f"Failed to create signature: {e}") from e

    # Build signature metadata
    signed_metadata = SignedMetadata(
        canonicalization="RFC8785",
        digest=event_digest,
        target="/event",
    )

    # Build signature
    alg = "ES256"
    if isinstance(private_key, Ed25519PrivateKey):
        alg = "EdDSA"

    signature = Signature(
        role=role,
        signer=signer_did,
        alg=alg,
        signed=signed_metadata,
        jws=jws,
    )

    # Build receipt
    return MailioReceipt(
        type="MailioReceipt",
        v="v1",
        event=event,
        event_digest=event_digest,
        signatures=(signature,),
    )


def compute_chain_digest(source: MailioReceipt | MailioAuditEvent) -> str:
    """
    Compute a chain digest from an event or receipt.

    For chaining, we only digest the event content (not signatures).
    """
    if isinstance(source, MailioReceipt):
        if source.event_digest:
            return source.event_digest
        event = source.event
    else:
        event = source
    return compute_digest(event.to_dict())


def chain_from(
    source: MailioReceipt | MailioAuditEvent,
    *,
    prev_receipt_ref: str | None = None,
    reason: str | None = None,
) -> Chain:
    """Create a Chain reference from a prior receipt or event."""
    return Chain(
        prev_receipt_digest=compute_chain_digest(source),
        prev_receipt_ref=prev_receipt_ref,
        reason=reason,
    )
