"""
Missing Receipt Types - To Be Added to receipts/models.py

These receipt types are documented in docs/receipts/RECEIPT-SCHEMAS.md
but were not yet implemented in the codebase.

This file provides the implementations. Once validated, these should be
merged into receipts/models.py.
"""

from __future__ import annotations
from datetime import datetime
from enum import Enum
from typing import Any, Dict, Literal, Optional, Union
from receipts.compat.pyd import BaseModel, ConfigDictLike, Field, field_validator
from receipts.base import BaseReceipt


# ============================================================================
# CompostStone - Failure Pattern Mining
# ============================================================================


class FailureType(str, Enum):
    """Type of failure captured in CompostStone."""
    GATE_VIOLATION = "gate_violation"
    OUTCOME_DIVERGENCE = "outcome_divergence"
    REFUSAL_CLUSTER = "refusal_cluster"
    SILENT_DEGRADATION = "silent_degradation"


class GateViolation(BaseModel):
    """Details of a gate violation."""
    model_config = ConfigDictLike(frozen=True, protected_namespaces=())

    gate_name: str
    threshold: float
    actual_value: float
    margin: float  # How far off (negative if below threshold)


class DivergenceDetail(BaseModel):
    """Details of prediction vs outcome divergence."""
    model_config = ConfigDictLike(frozen=True, protected_namespaces=())

    predicted_p: float
    predicted_ci90: tuple[float, float]
    realized_outcome: int  # 0 or 1
    surprise_magnitude: float  # Distance from CI


class FailureSignature(BaseModel):
    """Compact embedding for failure search and clustering."""
    model_config = ConfigDictLike(frozen=True, protected_namespaces=())

    feature_hash: str  # SHA256 of key features
    cohort_hash: str  # SHA256 of cohort_id
    gate_pattern: str  # e.g., "ECE+COHERENCE" or "DIGNITY"
    domain: str
    timestamp_bucket: str  # e.g., "2025-11-W44" (weekly bucket)


class CompostStone(BaseReceipt):
    """
    Failure wisdom receipt - captures pattern from prediction failures.

    Minted when:
    - ProphecyStone fails gates (ECE, DWF, calibration_gap)
    - Outcome diverges significantly from prediction
    - Multiple refusals cluster in same cohort

    Purpose:
    - Pattern recognition across failures
    - Searchable by features, cohort, gate violation
    - Feeds into model retraining
    - Resurrection hypotheses for future fixes
    """
    receipt_type: Literal["CompostStone"] = "CompostStone"

    # Failure context
    failure_type: FailureType
    parent_prophecy_id: Optional[str] = None  # If from ProphecyStone
    parent_refusal_id: Optional[str] = None  # If from RefusalStone

    # Prediction context
    domain: str  # "ncaab", "stocks", "mlb", etc.
    cohort_id: str
    features_snapshot: dict[str, Any]  # Anonymized features
    prediction_snapshot: Optional[dict[str, Any]] = None  # If ProphecyStone failure

    # Gate failure details
    gate_violations: list[GateViolation]

    # Outcome divergence (if applicable)
    divergence: Optional[DivergenceDetail] = None

    # Failure signature (for search and clustering)
    failure_signature: FailureSignature

    # Remediation hints
    suggested_actions: list[str]
    similar_failures: list[str] = []  # Receipt IDs of similar past failures

    # Cluster info (if part of refusal cluster)
    cluster_id: Optional[str] = None
    cluster_size: Optional[int] = None


# ============================================================================
# AuditReceipt - Self-Audit Verification Results
# ============================================================================


class AuditType(str, Enum):
    """Type of audit check performed."""
    LINEAGE = "lineage"
    DIGNITY = "dignity"
    CALIBRATION = "calibration"
    SIGNATURE = "signature"
    WITNESS = "witness"
    ANCHOR = "anchor"  # Merkle anchor replay verification
    LIVENESS = "liveness"  # Witness sample liveness checks
    TEMPORAL_CONSISTENCY = "temporal_consistency"
    COMPLETENESS = "completeness"
    GATE_ENFORCEMENT = "gate_enforcement"


class AuditStatus(str, Enum):
    """Overall audit status."""
    PASS = "PASS"
    FAIL = "FAIL"
    WARNING = "WARNING"


class AuditCheck(BaseModel):
    """Individual audit check result."""
    model_config = ConfigDictLike(frozen=True, protected_namespaces=())

    name: str
    receipts_checked: int
    violations: int
    details: Optional[dict[str, Any]] = None


class AuditReceipt(BaseReceipt):
    """
    Self-audit verification receipt.

    Minted by:
    - Scheduled self-audit jobs (daily/weekly)
    - On-demand audit runs
    - CI/CD pipeline checks

    Purpose:
    - Verify receipt chain integrity
    - Check signature validity
    - Validate gate enforcement
    - Monitor witness liveness
    - Detect drift/degradation

    See: docs/rfc/RFC-003-SELF-AUDIT.md
    """
    receipt_type: Literal["AuditReceipt"] = "AuditReceipt"

    audit_type: AuditType
    checks: list[AuditCheck]
    status: AuditStatus

    # Time window audited
    window_start: datetime
    window_end: datetime

    # Summary metrics
    total_receipts_checked: int
    total_violations: int

    # Violations details (if any)
    violation_receipt_ids: list[str] = []
    violation_summary: Optional[str] = None

    # Remediation (if violations found)
    recommended_actions: list[str] = []


# ============================================================================
# PolicyReceipt - Gate Definition Versioning
# ============================================================================


class GateDefinition(BaseModel):
    """Single gate definition."""
    model_config = ConfigDictLike(frozen=True, protected_namespaces=())

    name: str
    threshold: Union[float, Dict[str, float]]  # Can be domain-specific (Python 3.9 compatible)
    refusal_reason: str


class PolicyReceipt(BaseReceipt):
    """
    Gate policy versioning receipt.

    Minted when:
    - Gate thresholds change (e.g., DWF 0.70 → 0.75)
    - New gates added
    - Gates deprecated
    - Gatebook YAML updated

    Purpose:
    - Audit trail for policy changes
    - Link predictions to exact gate versions
    - Rollback support
    - Compliance evidence

    See: docs/rfc/RFC-005-GATEBOOK.md
    """
    receipt_type: Literal["PolicyReceipt"] = "PolicyReceipt"

    policy_id: str  # e.g., "gates_v2.3"
    policy_version: str  # Semver: "2.3.0"
    policy_text: str  # SIGIL or YAML source
    gates: list[GateDefinition]

    # Change metadata
    changes_from_previous: Optional[str] = None  # e.g., "Raised DWF threshold to 0.75"
    backtest_results: Optional[dict[str, Any]] = None  # Impact analysis
    approved_by: Optional[str] = None  # Gate Review Board member


# ============================================================================
# ConformalCoverageReceipt - Conformal Prediction Validation
# ============================================================================


class ConformalCoverageReceipt(BaseReceipt):
    """
    Conformal prediction coverage receipt (Enhanced with witnesses - A13).

    Minted when:
    - Conformal calibration completes
    - Coverage validation runs
    - Conformity scores computed

    Purpose:
    - Validate empirical coverage matches target
    - Ensure prediction intervals are honest
    - Detect coverage drift
    - Self-verifiable via witness hashes

    Enhancements (A13 from INNOVATION_OPPORTUNITIES_NOV2025.md):
    - Added conformity_scores_hash for verification
    - Added group_quantiles for stratified conformal
    - Added witness_sample_hash for reproducibility

    See: tests/receipts/test_conformal_receipt.py
    """
    receipt_type: Literal["ConformalCoverageReceipt"] = "ConformalCoverageReceipt"

    # Conformal prediction parameters
    target_coverage: float  # e.g., 0.90 (90% CI)
    empirical_coverage: float  # Actual coverage observed
    calibration_size: int  # Number of calibration samples

    # Conformity scores
    conformity_scores_quantile: float  # Quantile used (e.g., 0.90)

    # A13: Witness fields for self-verification
    conformity_scores_hash: Optional[str] = None  # SHA256 hash of calibration scores
    group_quantiles: Optional[Dict[str, float]] = None  # Per-cohort quantiles (Python 3.9 compatible)
    witness_sample_hash: Optional[str] = None  # Hash of witness sample subset

    # Validation
    matches_theory: bool  # Is empirical ≈ target within tolerance?
    coverage_tolerance: float = 0.02  # ±2% by default

    # Cohort-specific (optional)
    cohort_id: Optional[str] = None

    @field_validator("target_coverage", "empirical_coverage")
    @classmethod
    def validate_coverage_range(cls, v):
        """Coverage must be in [0, 1]."""
        if not 0 <= v <= 1:
            raise ValueError(f"Coverage must be in [0, 1], got {v}")
        return v

    @field_validator("calibration_size")
    @classmethod
    def validate_calibration_size(cls, v):
        """Calibration size must be positive."""
        if v <= 0:
            raise ValueError(f"Calibration size must be > 0, got {v}")
        return v

    def can_self_verify(self) -> bool:
        """Check if receipt has enough witness data for self-verification."""
        return (
            self.conformity_scores_hash is not None
            and self.witness_sample_hash is not None
        )


# ============================================================================
# SheetsFailureReceipt - Sheets API Error Tracking
# ============================================================================


class SheetsFailureReceipt(BaseReceipt):
    """
    Receipt documenting Google Sheets API failures for transparency.

    Emitted when:
    - batch_update_values() encounters API errors (403, 429, 404, etc.)
    - Credentials expire or become invalid
    - Network/quota issues prevent tile updates

    Purpose:
    - Track Sheets API reliability (fallback from Sheets to Parquet-only)
    - Audit trail for TrustReport tile update failures
    - Alert operators to credential/quota issues
    - Document graceful degradation (receipts still written to Parquet)
    """

    receipt_type: Literal["SheetsFailureReceipt"] = "SheetsFailureReceipt"

    # Error context
    operation: str = Field(
        description="Sheets operation that failed (batch_update_values, append_receipt_row, etc.)"
    )
    error_code: Optional[int] = Field(
        default=None, description="HTTP status code from Google Sheets API (403, 429, 404, etc.)"
    )
    error_message: str = Field(description="Error message from exception")

    # Affected ranges (for batch_update_values)
    affected_ranges: list[str] = Field(
        default_factory=list, description="Sheet ranges that failed to update (e.g., 'TrustReport!B3')"
    )

    # Fallback status
    parquet_fallback: bool = Field(
        default=True,
        description="Whether receipt was successfully written to Parquet despite Sheets failure",
    )

    # Remediation hints
    retry_recommended: bool = Field(
        default=False, description="Whether retry is recommended (e.g., for 429 rate limit errors)"
    )
    credential_issue: bool = Field(
        default=False, description="Whether error indicates credential/permission problem"
    )


# ============================================================================
# Export All
# ============================================================================

__all__ = [
    "FailureType",
    "GateViolation",
    "DivergenceDetail",
    "FailureSignature",
    "CompostStone",
    "AuditType",
    "AuditStatus",
    "AuditCheck",
    "AuditReceipt",
    "GateDefinition",
    "PolicyReceipt",
    "ConformalCoverageReceipt",
    "SheetsFailureReceipt",
]
