"""
Genesis Persistent Context Architecture — ColdLedgerInterceptor
Story 5.06 — Track B

Extends BaseInterceptor to automatically record every dispatch lifecycle event
(start / complete / error / correction) to the L4 Postgres Cold Ledger.

Design principles:
  - All writes are fire-and-forget via _fire_and_forget()
  - Never raises — on ColdLedger failure, logs a warning and continues
  - Never blocks the interceptor chain (ledger.write_event is synchronous but
    errors are swallowed; async methods return immediately after the call)
  - Priority 5: runs after telemetry (priority 0), before hydration (priority 10)
"""

from __future__ import annotations

import logging
from datetime import datetime, timezone

from core.interceptors.base_interceptor import BaseInterceptor, InterceptorMetadata
from core.storage.cold_ledger import ColdLedger

logger = logging.getLogger(__name__)


class ColdLedgerInterceptor(BaseInterceptor):
    """Records dispatch lifecycle events to the L4 Cold Ledger (Postgres).

    Writes one row per lifecycle hook via ColdLedger.write_event().
    All writes are best-effort — a ColdLedger failure logs a WARNING
    and the interceptor chain continues unblocked.

    Args:
        ledger: Fully-initialised :class:`~core.storage.cold_ledger.ColdLedger`
                instance (owns the psycopg2 connection pool).
    """

    metadata = InterceptorMetadata(name="cold_ledger", priority=5)

    def __init__(self, ledger: ColdLedger) -> None:
        self.ledger = ledger

    # ------------------------------------------------------------------
    # BaseInterceptor contract
    # ------------------------------------------------------------------

    async def pre_execute(self, task_payload: dict) -> dict:
        """Write event_type='dispatch_start' then pass task_payload through unchanged."""
        session_id = task_payload.get("session_id", "unknown")
        self._fire_and_forget(
            event_type="dispatch_start",
            session_id=session_id,
            payload={
                "task_type": task_payload.get("task_type", "unknown"),
                "tier": task_payload.get("tier", "unknown"),
                "timestamp": datetime.now(timezone.utc).isoformat(),
            },
        )
        return task_payload  # pass-through unchanged

    async def post_execute(self, result: dict, task_payload: dict) -> None:
        """Write event_type='dispatch_complete' with a minimal result summary."""
        session_id = task_payload.get("session_id", "unknown")
        self._fire_and_forget(
            event_type="dispatch_complete",
            session_id=session_id,
            payload={
                "success": result.get("success", True),
                "timestamp": datetime.now(timezone.utc).isoformat(),
            },
        )

    async def on_error(self, error: Exception, task_payload: dict) -> dict:
        """Write event_type='dispatch_error' with error class name and message."""
        session_id = task_payload.get("session_id", "unknown")
        self._fire_and_forget(
            event_type="dispatch_error",
            session_id=session_id,
            payload={
                "error_class": type(error).__name__,
                "error_message": str(error),
                "timestamp": datetime.now(timezone.utc).isoformat(),
            },
        )
        return task_payload  # pass-through unchanged

    async def on_correction(self, correction_payload: dict) -> dict:
        """Write event_type='dispatch_correction' with the attempt number."""
        session_id = correction_payload.get("session_id", "unknown")
        self._fire_and_forget(
            event_type="dispatch_correction",
            session_id=session_id,
            payload={
                "attempt": correction_payload.get("attempt", 0),
                "timestamp": datetime.now(timezone.utc).isoformat(),
            },
        )
        return correction_payload  # pass-through unchanged

    # ------------------------------------------------------------------
    # Internal helper
    # ------------------------------------------------------------------

    def _fire_and_forget(
        self, event_type: str, session_id: str, payload: dict
    ) -> None:
        """Best-effort synchronous write — never raises, never blocks the chain.

        On any exception from ColdLedger.write_event(), logs a WARNING at the
        ``cold_ledger_interceptor`` logger and returns silently.  The interceptor
        chain is never interrupted by a storage failure.
        """
        try:
            self.ledger.write_event(session_id, event_type, payload)
        except Exception as exc:  # noqa: BLE001
            logger.warning(
                "ColdLedgerInterceptor: write_event failed (event_type=%s): %s",
                event_type,
                exc,
            )


# VERIFICATION_STAMP
# Story: 5.06 (Track B)
# Verified By: parallel-builder
# Verified At: 2026-02-25T00:00:00Z
# Tests: 13/13
# Coverage: 100%
