"""Shared test fixtures for MailioReceipt tests."""

from __future__ import annotations

import uuid
from datetime import datetime, timezone
from typing import TYPE_CHECKING, Any

import pytest
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey


if TYPE_CHECKING:
    from cryptography.hazmat.primitives.asymmetric.ec import (
        EllipticCurvePrivateKey,
        EllipticCurvePublicKey,
    )

from mailio_receipt.models import (
    Actors,
    Intent,
    IntentKind,
)
from mailio_receipt import chain_from, create_event, create_receipt
from mailio_receipt.models import MailioReceipt


@pytest.fixture
def agent_private_key() -> EllipticCurvePrivateKey:
    """Generate an EC P-256 private key for agent signing."""
    return ec.generate_private_key(ec.SECP256R1(), default_backend())


@pytest.fixture
def agent_public_key(agent_private_key: EllipticCurvePrivateKey) -> EllipticCurvePublicKey:
    """Get public key from agent private key."""
    return agent_private_key.public_key()


@pytest.fixture
def user_private_key() -> EllipticCurvePrivateKey:
    """Generate an EC P-256 private key for user signing."""
    return ec.generate_private_key(ec.SECP256R1(), default_backend())


@pytest.fixture
def user_public_key(user_private_key: EllipticCurvePrivateKey) -> EllipticCurvePublicKey:
    """Get public key from user private key."""
    return user_private_key.public_key()


@pytest.fixture
def agent_did() -> str:
    """Sample agent DID."""
    return "did:web:agent.example.com"


@pytest.fixture
def user_did() -> str:
    """Sample user DID."""
    return "did:web:user.example.com"


@pytest.fixture
def sample_actors(agent_did: str, user_did: str) -> Actors:
    """Sample actors for testing."""
    return Actors(
        issuer=agent_did,
        subject=user_did,
    )


@pytest.fixture
def sample_intent() -> Intent:
    """Sample intent for testing."""
    return Intent(
        kind=IntentKind.ACTION_PLANNED,
        action="invoice.send",
        category="financial",
        scope={
            "invoiceId": "INV-2026-001",
            "amount": 1500.00,
            "currency": "USD",
        },
    )


@pytest.fixture
def sample_approval_intent() -> Intent:
    """Sample approval intent for testing."""
    return Intent(
        kind=IntentKind.APPROVAL_GRANTED,
        action="invoice.send",
        category="financial",
        scope={
            "purpose": "approval.before-send",
        },
    )


@pytest.fixture
def sample_revocation_intent() -> Intent:
    """Sample revocation intent for testing."""
    return Intent(
        kind=IntentKind.APPROVAL_REVOKED,
        action="invoice.send",
        category="financial",
        scope={
            "reason": "Changed mind",
        },
    )


@pytest.fixture
def sample_flow_id() -> str:
    """Sample flow ID for testing."""
    return str(uuid.uuid4())


@pytest.fixture
def sample_timestamp() -> datetime:
    """Sample timestamp for testing."""
    return datetime(2026, 2, 4, 15, 30, 0, 123456, tzinfo=timezone.utc)


@pytest.fixture
def sample_event_id() -> str:
    """Sample event ID for testing."""
    return str(uuid.uuid4())

@pytest.fixture
def ed25519_agent_private_key() -> Ed25519PrivateKey:
    """Generate an Ed25519 private key for agent signing."""
    return Ed25519PrivateKey.generate()

@pytest.fixture
def ed25519_agent_public_key(ed25519_agent_private_key: Ed25519PrivateKey) -> Ed25519PublicKey:
    """Get public key from agent private key."""
    return ed25519_agent_private_key.public_key()


def build_approval_receipt(
    *,
    planned_receipt: MailioReceipt,
    flow_id: str,
    actors: Actors,
    private_key: EllipticCurvePrivateKey | Ed25519PrivateKey,
    signer_did: str,
    ttl: str | None = None,
    scope: dict[str, Any] | None = None,
    role: str = "user",
) -> MailioReceipt:
    intent_scope = {"approvedReceiptDigest": planned_receipt.event_digest}
    if scope:
        intent_scope.update(scope)
    intent = Intent(
        kind=IntentKind.APPROVAL_GRANTED,
        action=planned_receipt.event.intent.action,
        category=planned_receipt.event.intent.category,
        scope=intent_scope,
    )
    event = create_event(
        flow_id=flow_id,
        actors=actors,
        intent=intent,
        chain=chain_from(planned_receipt),
        ttl=ttl,
    )
    return create_receipt(
        event=event,
        private_key=private_key,
        signer_did=signer_did,
        role=role,
    )


def build_revocation_receipt(
    *,
    approval_receipt: MailioReceipt,
    flow_id: str,
    actors: Actors,
    private_key: EllipticCurvePrivateKey | Ed25519PrivateKey,
    signer_did: str,
    scope: dict[str, Any] | None = None,
    role: str = "user",
) -> MailioReceipt:
    intent_scope = {"revokedApprovalDigest": approval_receipt.event_digest}
    if scope:
        intent_scope.update(scope)
    intent = Intent(
        kind=IntentKind.APPROVAL_REVOKED,
        action=approval_receipt.event.intent.action,
        category=approval_receipt.event.intent.category,
        scope=intent_scope,
    )
    event = create_event(
        flow_id=flow_id,
        actors=actors,
        intent=intent,
        chain=chain_from(approval_receipt),
    )
    return create_receipt(
        event=event,
        private_key=private_key,
        signer_did=signer_did,
        role=role,
    )


def build_execution_outcome_receipt(
    *,
    approval_receipt: MailioReceipt,
    flow_id: str,
    actors: Actors,
    success: bool,
    private_key: EllipticCurvePrivateKey | Ed25519PrivateKey,
    signer_did: str,
    failure_reason: str | None = None,
    failure_code: str | None = None,
    scope: dict[str, Any] | None = None,
    role: str = "agent",
) -> MailioReceipt:
    outcome_scope: dict[str, Any] = {"approvalDigest": approval_receipt.digest}
    if success:
        intent_kind = IntentKind.ACTION_EXECUTED
        outcome_scope["result"] = "success"
    else:
        intent_kind = IntentKind.ACTION_FAILED
        outcome_scope["result"] = "failure"
        if failure_reason:
            outcome_scope["failureReason"] = failure_reason
        if failure_code:
            outcome_scope["failureCode"] = failure_code
    if scope:
        outcome_scope.update(scope)

    intent = Intent(
        kind=intent_kind,
        action=approval_receipt.event.intent.action,
        category=approval_receipt.event.intent.category,
        scope=outcome_scope,
    )
    event = create_event(
        flow_id=flow_id,
        actors=actors,
        intent=intent,
        chain=chain_from(approval_receipt),
    )
    return create_receipt(
        event=event,
        private_key=private_key,
        signer_did=signer_did,
        role=role,
    )

@pytest.fixture
def ed25519_user_private_key() -> Ed25519PrivateKey:
    """Generate an Ed25519 private key for user signing."""
    return Ed25519PrivateKey.generate()

@pytest.fixture
def ed25519_user_public_key(ed25519_user_private_key: Ed25519PrivateKey) -> Ed25519PublicKey:
    """Get public key from user private key."""
    return ed25519_user_private_key.public_key()
