"""
kaskad/types.py — Core types for the Generative Cascade Engine.

Models the cascade structure (AX23) where Names form a DAG and each
motivates the next via internal necessity.  The same typed-edge DAG
structure is used for the framework's own Inference Graph (§IG).

Governing axioms and theorems:
  AX23:  Names form a DAG; kaskad relation is transitive
  AX24:  Self-Love of Beauty — Beauty is intrinsically lovable
  AX25:  Desire-to-Show — Beauty desires mirrors
  T7:    Creation Motor — creation exists because Beauty desires mirrors
  T8:    Cascade Neighborliness — detecting n₁ predicts detectability of n₂
  AX63:  Tesanüd — affirmations compose super-additively; denials isolated

Inference Graph references (§IG.1–IG.5):
  6 typed edge morphisms: proves, grounds, constrains, gates, calibrates, combines
  7 primary chains: C1–C7
  Hub nodes: KV₄, OR-2, T6, AX58
"""

from __future__ import annotations

import enum
from dataclasses import dataclass, field
from typing import (
    Any,
    Dict,
    FrozenSet,
    List,
    Optional,
    Sequence,
    Set,
    Tuple,
)


# ========================================================================
# Enums
# ========================================================================

class EdgeType(enum.Enum):
    """
    §IG.1 — Six typed morphisms connecting framework elements.

    Each edge in the cascade DAG has exactly one type.
    """
    PROVES     = "proves"       # →ₚ  Axiom(s) → Theorem
    GROUNDS    = "grounds"      # →ᵍ  Element → Element
    CONSTRAINS = "constrains"   # →꜀  Kavaid → Element
    GATES      = "gates"        # →ᵍₜ Element → OutputRule
    CALIBRATES = "calibrates"   # →ₖ  Nuance → Element
    COMBINES   = "combines"     # →⊕  {Elements} → Result


class NodeKind(enum.Enum):
    """Classification of nodes in the framework DAG."""
    AXIOM       = "axiom"
    THEOREM     = "theorem"
    KAVAID      = "kavaid"
    OUTPUT_RULE = "output_rule"
    METHOD_RULE = "method_rule"
    NUANCE      = "nuance"
    SECTION     = "section"      # §-reference (e.g., §7.2)
    NAME        = "name"         # S_Isim member (for beauty cascade)
    SEUN        = "seun"         # S_Seun member (dispositional root)


class ChainId(enum.Enum):
    """
    §IG.2 — The 7 primary inference chains.
    """
    C1 = "C1_ontological_poverty_provision"
    C2 = "C2_beauty_creation"
    C3 = "C3_holographic_participation_convergence"
    C4 = "C4_faculties_coverage_incompleteness"
    C5 = "C5_station_hierarchy_limits"
    C6 = "C6_names_dual_meaning_harfi"
    C7 = "C7_continuous_degrees_supremum_bound"

    # The beauty cascade is both a concrete instance and a meta-chain
    BEAUTY_CASCADE = "beauty_cascade_9level"


# ========================================================================
# Dataclasses
# ========================================================================

@dataclass(frozen=True)
class CascadeNode:
    """
    A node in the cascade DAG.

    Each node has:
      - id: unique identifier (e.g., "AX23", "T7", "KV₄")
      - kind: classification (axiom, theorem, etc.)
      - label: human-readable short description
      - chains: which inference chains this node belongs to
    """
    id: str
    kind: NodeKind
    label: str
    chains: FrozenSet[ChainId] = field(default_factory=frozenset)

    def __hash__(self) -> int:
        return hash(self.id)

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, CascadeNode):
            return NotImplemented
        return self.id == other.id


@dataclass(frozen=True)
class CascadeEdge:
    """
    A typed directed edge in the cascade DAG.

    AX23: kaskad(a,b) ∧ kaskad(b,c) → kaskad(a,c)  [transitivity]
    §IG.1: every edge has exactly one EdgeType.
    """
    source: str     # node id
    target: str     # node id
    edge_type: EdgeType
    label: str = ""

    def __hash__(self) -> int:
        return hash((self.source, self.target, self.edge_type))

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, CascadeEdge):
            return NotImplemented
        return (
            self.source == other.source
            and self.target == other.target
            and self.edge_type == other.edge_type
        )


@dataclass
class DynamicEdge:
    """
    A cascade edge with dynamic activation strength.

    Phase 7 (BS-19/BS-20): The DAG topology (AX23) is axiomatic and
    immutable — nodes and edges never change.  What DOES change is
    the *activation* of each edge, modulated by content evidence.

    base_strength:  Structural baseline (always 1.0 — axiomatic)
    activation:     Content-dependent activation in [MIN_ACTIVATION, 1.0]
    effective_strength:  base_strength × activation

    The minimum activation is 0.3 — a structural edge is always real,
    even if the current text provides no evidence for it.
    """
    source: str
    target: str
    edge_type: EdgeType
    base_strength: float = 1.0
    activation: float = 1.0

    MIN_ACTIVATION: float = 0.3

    @property
    def effective_strength(self) -> float:
        """Effective edge strength: base × activation."""
        return self.base_strength * self.activation

    @classmethod
    def from_edge(cls, edge: "CascadeEdge", activation: float = 1.0) -> "DynamicEdge":
        """Wrap a frozen CascadeEdge with dynamic activation."""
        clamped = max(cls.MIN_ACTIVATION, min(1.0, activation))
        return cls(
            source=edge.source,
            target=edge.target,
            edge_type=edge.edge_type,
            activation=clamped,
        )


@dataclass
class NeighborhoodPrediction:
    """
    T8 — Cascade Neighborliness prediction result.

    Given a set of detected nodes, predicts which cascade neighbors
    should be predictably detectable (T8).
    """
    detected: FrozenSet[str]            # initially detected node IDs
    predicted: FrozenSet[str]           # predicted detectable via T8
    confidence: float                    # 0 < confidence < 1 (T6 bound)
    chain_coverage: Dict[ChainId, float]  # per-chain coverage ratio


@dataclass
class HubAnalysis:
    """
    §IG.3 — Hub node analysis.

    Hub = node with highest in-degree across multiple chains.
    """
    node_id: str
    in_degree: int
    out_degree: int
    chain_count: int
    chains: FrozenSet[ChainId]
    is_bridge: bool   # shared between ≥2 chains → bridge node


@dataclass
class ChainIntegrity:
    """
    Integrity report for a single inference chain.

    Validates:
      - Acyclicity (DAG property)
      - Transitivity (AX23)
      - Connectivity (no orphan nodes within a chain)
      - Grounded outputs (every OR has a derivation path)
    """
    chain_id: ChainId
    is_acyclic: bool
    is_connected: bool
    node_count: int
    edge_count: int
    source_nodes: FrozenSet[str]    # nodes with in-degree 0
    sink_nodes: FrozenSet[str]      # nodes with out-degree 0
    max_depth: int                   # longest path length


@dataclass
class TesanudResult:
    """
    AX63 — Tesanüd (super-additive composition) measurement.

    When independent chains converge on the same node (KV₇ satisfied),
    the evidence is super-additive (tesanüd).
    When they diverge, denials remain isolated (infirâdî).
    """
    node_id: str
    converging_chains: FrozenSet[ChainId]
    chain_count: int
    is_tesanud: bool          # True if ≥2 independent chains converge
    is_infiradi: bool         # True if only 1 chain (isolated finding)
    composition_mode: str     # "super_additive" | "isolated" | "n/a"


@dataclass
class CascadeReport:
    """
    Full cascade analysis report — analogous to bileshke's QualityReport.

    AX57: Transparency — all structural properties disclosed.
    """
    total_nodes: int
    total_edges: int
    chain_count: int
    chain_integrity: Dict[ChainId, ChainIntegrity]
    hub_nodes: List[HubAnalysis]
    bridge_nodes: List[str]
    tesanud_nodes: List[TesanudResult]
    topological_order: List[str]
    max_depth: int
    # KV₄ check: cascade analysis itself participates in truth
    # without being identical to it
    structural_completeness: float  # always < 1.0
