"""
Universal Tiering + CloudEvents Bridge helpers.

Implements Pattern 2 (Five-Tier Retention):
    TRANSIENT  → in-memory only
    OPERATIONAL → SQLite hot tier (1-day retention)
    RECORDED   → Parquet cold tier (30+ days)
    SIGNED     → Cold tier + cryptographic signing
    LEGAL      → Cold tier + signing + CourtPacket artifact
"""

from __future__ import annotations

import base64
import json
import logging
from datetime import datetime, timezone
from pathlib import Path
from typing import Callable, Optional, Tuple

from alerts.tiering import AlertTier
from receipts.base_event import BaseEvent

try:
    from tools.crypto.signing import KeyStore
except Exception:  # pragma: no cover - optional dependency
    KeyStore = None  # type: ignore

logger = logging.getLogger(__name__)


def route_by_tier(event: BaseEvent) -> Tuple[str, bool]:
    """
    Route events to storage backends based on AlertTier.

    Returns:
        backend: "memory" | "sqlite_hot" | "parquet_cold"
        needs_signing: True if SIGNED/LEGAL tier requires signature
    """
    tier = event.tier
    if tier == AlertTier.TRANSIENT:
        return "memory", False

    if tier == AlertTier.OPERATIONAL:
        return "sqlite_hot", False

    needs_signing = tier.value >= AlertTier.SIGNED.value
    return "parquet_cold", needs_signing


def sign_if_needed(
    event: BaseEvent,
    *,
    keystore_root: Optional[Path] = None,
    environment: str = "dev",
    signer: Optional[Callable[[bytes], str]] = None,
) -> BaseEvent:
    """
    Apply Ed25519 signing only for SIGNED/LEGAL tiers.

    Args:
        event: BaseEvent to sign
        keystore_root: Optional override for keystore location (default var/keys)
        environment: Key namespace (dev/staging/prod)
        signer: Optional callable returning signature string for tests
    """
    if event.tier.value < AlertTier.SIGNED.value:
        return event

    if event.signature:
        return event

    payload = event.to_json().encode("utf-8")

    if signer:
        event.signature = signer(payload)
        return event

    if KeyStore is None:
        logger.warning("Signing skipped: KeyStore unavailable")
        return event

    try:
        keystore_root = keystore_root or Path("var/keys")
        keystore = KeyStore(keystore_root, environment=environment)
        key_id, signing_key = keystore.get_active_key()
        signed = signing_key.sign(payload)
        signature_b64 = base64.b64encode(signed.signature).decode("ascii")
        event.signature = f"ed25519:{signature_b64}"
        logger.debug("Signed event %s with %s", event.event_id, key_id)
    except Exception as exc:  # pragma: no cover - best effort
        logger.warning("Signing skipped for %s: %s", event.event_id, exc)

    return event


def generate_court_packet(
    event: BaseEvent,
    *,
    output_dir: Path = Path("court_packets"),
) -> Optional[Path]:
    """
    Generate lightweight CourtPacket manifest for LEGAL tier events.

    Returns:
        Path to generated JSON manifest, or None if tier < LEGAL.
    """
    if event.tier != AlertTier.LEGAL:
        return None

    output_dir.mkdir(parents=True, exist_ok=True)
    packet_path = output_dir / f"{event.event_id}_court_packet.json"

    manifest = {
        "event_id": event.event_id,
        "tier": event.tier.name,
        "generated_at": datetime.now(timezone.utc).isoformat(),
        "dip_hash": event.dip_hash,
        "tenant_id": event.tenant_id,
        "namespaces": event.namespaces,
        "chi_score": event.chi_score,
        "dignity_score": event.dignity_score,
        "proofs": {
            "signature": event.signature,
            "traceparent": event.traceparent,
        },
        "payload": event.to_dict(),
        "verification": {
            "offline": True,
            "acs_score": 1.0,
            "instructions": "Verify signature + DIP hash + timestamp chain"
        }
    }

    with open(packet_path, "w") as f:
        json.dump(manifest, f, indent=2)

    logger.info("CourtPacket manifest created for %s → %s", event.event_id, packet_path)
    return packet_path
