"""
Helper pipeline for tri-temporal receipts:
- Validate against schema
- Attach lineage
- Sign and optionally timestamp via RFC 3161

This does not write to disk; it prepares a tri-temporal receipt for emission.
"""

from __future__ import annotations

import base64
import os
from typing import Optional, Tuple

from jsonschema.exceptions import ValidationError as JSONSchemaValidationError

from receipts.schema_registry import get_validator
from receipts.tri_temporal import (
    TRI_TEMPORAL_SCHEMA_ID,
    TriTemporalReceipt,
    attach_lineage,
    sign_and_timestamp_receipt,
)


class TriTemporalSigningError(RuntimeError):
    """Raised when signing is required but no key is provided."""


def _load_signing_key(signing_key_b64: Optional[str]):
    """Load nacl SigningKey from base64; returns None if not provided."""
    try:
        from nacl.signing import SigningKey
    except Exception:  # pragma: no cover - optional dependency
        return None

    key_b64 = signing_key_b64 or os.getenv("LOOM_ED25519_SIGNING_KEY_B64")
    if not key_b64:
        return None
    return SigningKey(base64.b64decode(key_b64))


def prepare_tri_temporal_receipt(
    receipt: TriTemporalReceipt,
    *,
    parent_hash: Optional[str] = None,
    parent_merkle_root: Optional[str] = None,
    parent_transaction_time=None,
    signing_key_b64: Optional[str] = None,
    use_stub_tsa: bool = True,
) -> Tuple[TriTemporalReceipt, str]:
    """
    Validate, lineage-link, and sign a tri-temporal receipt.

    Args:
        receipt: TriTemporalReceipt to process.
        parent_hash: Optional parent receipt hash (prefixed, e.g., sha256:...).
        parent_merkle_root: Optional parent Merkle root for roll-forward linkage.
        parent_transaction_time: Optional parent transaction_time for temporal guard.
        signing_key_b64: Base64 Ed25519 signing key; falls back to LOOM_ED25519_SIGNING_KEY_B64.
        use_stub_tsa: Use stub TSA when no TSA server is configured.

    Returns:
        (final_receipt, payload_hash)
    """
    # Ensure dataschema is set
    if not receipt.dataschema:
        receipt = receipt.model_copy(update={"dataschema": TRI_TEMPORAL_SCHEMA_ID})

    # Schema validation
    try:
        validator = get_validator(TRI_TEMPORAL_SCHEMA_ID)
        validator.validate(receipt.model_dump(mode="json", exclude_none=True))
    except JSONSchemaValidationError as exc:
        raise ValueError(f"Tri-temporal receipt failed schema validation: {exc.message}") from exc

    # Attach lineage if provided
    if parent_hash or parent_merkle_root:
        receipt = attach_lineage(
            receipt,
            parent_hash=parent_hash,
            parent_merkle_root=parent_merkle_root,
            parent_transaction_time=parent_transaction_time,
        )

    # Sign + optional TSA
    signing_key = _load_signing_key(signing_key_b64)
    if signing_key is None:
        raise TriTemporalSigningError("Ed25519 signing key not available for tri-temporal receipt")

    signed = sign_and_timestamp_receipt(
        receipt,
        signing_key=signing_key,
        tsa_server=os.getenv("LOOM_TSA_SERVER"),
        use_stub_tsa=use_stub_tsa,
    )

    from receipts.tri_temporal import compute_receipt_hash

    payload_hash = compute_receipt_hash(signed, include_proof=False, include_lineage=False)
    return signed, payload_hash


__all__ = [
    "prepare_tri_temporal_receipt",
    "TriTemporalSigningError",
]
