"""
holografik.verification — Verification engine for the Topoloji + Holografik Lens (Lens #7 of 7).

Provides checks and a convergence score (yakinlasma) for holographic/topological
models.  Each check returns ``(passed: bool, detail: str)`` for
integration with the framework quality apparatus (AGENTS.md §5).

Checks implemented:
  - check_seed_structure:          22-dim seed vector validity
  - check_holographic_isomorphism: AX37 — parts mirror the whole
  - check_seed_omnipresence:       KV₆ — every module has seed > 0
  - check_fidelity_bounds:         T14/KV₄ — 0 < fidelity < 1
  - check_celal_inclusion:         N-2/AX59 — B21–B22 not excluded
  - check_convergence_bound:       KV₄/T6 — no score ≥ 1.0
  - check_tesanud_infirad:         AX63 — composition mode correct
  - check_independence:            KV₇ — units independently defined
  - check_transparency:            AX57 — model state fully inspectable

Governing axioms:
  AX37:    Holographic Structure (core axiom for this lens)
  KV₆:    Holographic Seed Omnipresence (core kavaid for this lens)
  T12:    Besmele Seed — triple isomorphism
  T14:    Ne Ayn Ne Gayr Chain — 0 < fidelity < 1
  AX52:   Multiplicative gate
  AX63:   Tesanüd/İnfirâd asymmetry
  KV₃:    Observer non-interference
  KV₄/T6: Convergence bound 0 < C < 1
  KV₇:    Independence

KV₇ compliance: This module imports ONLY from holografik.types
                 and the standard library.
"""

from __future__ import annotations

from typing import Dict, List, Optional, Tuple

from holografik.types import (
    ALL_DIMENSIONS,
    BesmeleBoyut,
    CELALI_DIMENSIONS,
    CompositionMode,
    DimensionType,
    DIMENSION_TYPE,
    FidelityPair,
    HolographicModel,
    HolographicUnit,
    IsomorphismResult,
    NUM_CELALI,
    NUM_CEMALI,
    NUM_DIMENSIONS,
    SeedVector,
    clamp_score,
)


# ---------------------------------------------------------------------------
# Individual verification checks
# ---------------------------------------------------------------------------

def check_seed_structure(
    model: Optional[HolographicModel] = None,
) -> Tuple[bool, str]:
    """Verify that all seed vectors have valid 22-dimensional structure.

    Each component must be a finite number, and the vector must have
    exactly NUM_DIMENSIONS (22) components.
    """
    if model is None or not model.units:
        return True, "No units to check (vacuously valid)"

    for unit in model.units:
        if len(unit.seed.values) != NUM_DIMENSIONS:
            return False, (
                f"Unit '{unit.name}' has {len(unit.seed.values)} dimensions, "
                f"expected {NUM_DIMENSIONS}"
            )
        for i, v in enumerate(unit.seed.values):
            if not isinstance(v, (int, float)) or (
                isinstance(v, float) and (v != v)
            ):  # NaN check
                return False, (
                    f"Unit '{unit.name}' dimension {i} has invalid value"
                )
    return True, f"All {len(model.units)} units have valid {NUM_DIMENSIONS}-dim seed vectors"


def check_holographic_isomorphism(
    model: Optional[HolographicModel] = None,
) -> Tuple[bool, str]:
    """AX37: Verify holographic isomorphism — parts mirror the whole.

    Checks that computed isomorphism results are structurally consistent:
    similarity is non-negative, shared_dimensions is valid, and at least
    some structural similarity exists between units.
    """
    if model is None:
        return True, "No model to check (vacuously valid)"

    results = model.isomorphism_results
    if not results:
        if len(model.units) < 2:
            return True, "Fewer than 2 units — isomorphism not applicable"
        return True, "No isomorphism results computed (vacuously valid)"

    for r in results:
        if r.similarity < 0:
            return False, (
                f"Negative similarity ({r.similarity:.4f}) between "
                f"'{r.unit_a_name}' and '{r.unit_b_name}'"
            )
        if r.shared_dimensions < 0 or r.shared_dimensions > NUM_DIMENSIONS:
            return False, (
                f"Invalid shared_dimensions ({r.shared_dimensions}) between "
                f"'{r.unit_a_name}' and '{r.unit_b_name}'"
            )

    iso_count = sum(1 for r in results if r.is_isomorphic)
    return True, (
        f"{iso_count}/{len(results)} pairs are isomorphic "
        f"(mean similarity: {model.mean_similarity:.4f})"
    )


def check_seed_omnipresence(
    model: Optional[HolographicModel] = None,
) -> Tuple[bool, str]:
    """KV₆: Every module must have a detectable holographic seed.

    HolographicConstant(module) > 0 for ALL modules.
    A zero-seed unit is a structural error.
    """
    if model is None or not model.units:
        return True, "No units to check (vacuously valid)"

    zero_units = [
        u.name for u in model.units if not u.seed.is_omnipresent
    ]
    if zero_units:
        return False, (
            f"KV₆ VIOLATION: {len(zero_units)} unit(s) have zero seed: "
            f"{', '.join(zero_units)}"
        )
    return True, f"All {len(model.units)} units have detectable seeds (KV₆ satisfied)"


def check_fidelity_bounds(
    model: Optional[HolographicModel] = None,
) -> Tuple[bool, str]:
    """T14/KV₄: All fidelity values must be strictly between 0 and 1.

    Per T14 (Ne Ayn Ne Gayr Chain):
    0 < Fidelity(source, derivative) < 1 at every level.
    """
    if model is None or not model.fidelity_pairs:
        return True, "No fidelity pairs to check (vacuously valid)"

    violations = []
    for p in model.fidelity_pairs:
        if p.fidelity <= 0 or p.fidelity >= 1:
            violations.append(
                f"({p.source_name} → {p.derivative_name}): {p.fidelity:.4f}"
            )

    if violations:
        return False, (
            f"T14 VIOLATION: {len(violations)} fidelity value(s) outside (0,1): "
            + "; ".join(violations)
        )

    return True, (
        f"All {len(model.fidelity_pairs)} fidelity pairs in valid range (0, 1)"
    )


def check_celal_inclusion(
    model: Optional[HolographicModel] = None,
) -> Tuple[bool, str]:
    """N-2/AX59: Celâlî dimensions (B21–B22) must not be excluded.

    The holographic seed includes both cemâlî (beauty) and celâlî
    (majesty/severity) dimensions.  Analysis must not exclude the latter.
    """
    if model is None or not model.units:
        return True, "No units to check (vacuously valid)"

    if not model.celal_included:
        return False, (
            "N-2/AX59 VIOLATION: No unit has non-zero celâlî dimensions "
            "(B21–B22). The holographic seed must include both cemâlî and celâlî."
        )

    units_with_celal = sum(
        1 for u in model.units if u.seed.has_celal
    )
    return True, (
        f"Celâl included: {units_with_celal}/{len(model.units)} units "
        f"have non-zero celâlî dimensions"
    )


def check_convergence_bound(
    model: Optional[HolographicModel] = None,
) -> Tuple[bool, str]:
    """KV₄/T6: No convergence score may reach 1.0.

    Checks structural bounds on all scores:
    - seed dimension values
    - fidelity values
    - similarity values
    """
    if model is None:
        return True, "No model to check (vacuously valid)"

    # Check seed values
    for unit in model.units:
        for i, v in enumerate(unit.seed.values):
            if v >= 1.0:
                return False, (
                    f"KV₄/T6 VIOLATION: Unit '{unit.name}' dimension "
                    f"{i} = {v} (must be < 1.0)"
                )

    # Check fidelity values
    for p in model.fidelity_pairs:
        if p.fidelity >= 1.0:
            return False, (
                f"KV₄/T6 VIOLATION: Fidelity "
                f"({p.source_name} → {p.derivative_name}) = {p.fidelity}"
            )

    # Check similarity values
    for r in model.isomorphism_results:
        if r.similarity >= 1.0:
            return False, (
                f"KV₄/T6 VIOLATION: Similarity "
                f"({r.unit_a_name}, {r.unit_b_name}) = {r.similarity}"
            )

    return True, "All scores bounded below 1.0"


def check_tesanud_infirad(
    model: Optional[HolographicModel] = None,
) -> Tuple[bool, str]:
    """AX63: Composition mode must be correctly classified.

    - TESANUD: requires multiple units with positive tesanüd strength
    - INFIRAD: findings remain isolated
    - INDEPENDENT: neutral
    """
    if model is None:
        return True, "No model to check (vacuously valid)"

    mode = model.composition_mode
    strength = model.tesanud_strength

    if mode == CompositionMode.TESANUD:
        if len(model.units) < 2:
            return False, (
                "AX63 VIOLATION: TESANUD requires ≥2 units, "
                f"got {len(model.units)}"
            )
        if strength <= 0:
            return False, (
                "AX63 VIOLATION: TESANUD but tesanüd strength = 0"
            )
        return True, f"TESANUD mode, strength = {strength:.4f}"

    if mode == CompositionMode.INFIRAD:
        return True, f"INFIRAD mode — findings remain isolated"

    return True, f"INDEPENDENT mode, strength = {strength:.4f}"


def check_independence(
    model: Optional[HolographicModel] = None,
) -> Tuple[bool, str]:
    """KV₇: Units must be independently defined.

    Checks that no two units share the exact same seed vector
    (which would indicate shared state / copy).
    """
    if model is None or len(model.units) < 2:
        return True, "Fewer than 2 units — independence trivially satisfied"

    units = model.units
    n = len(units)
    for i in range(n):
        for j in range(i + 1, n):
            if units[i].seed.values == units[j].seed.values:
                return False, (
                    f"KV₇ VIOLATION: '{units[i].name}' and '{units[j].name}' "
                    f"have identical seed vectors (shared state)"
                )

    return True, f"All {n} units have independent seed vectors"


def check_transparency(
    model: Optional[HolographicModel] = None,
) -> Tuple[bool, str]:
    """AX57: Model state must be fully inspectable via to_dict().

    Verifies the model can serialize to a dict that includes all
    required fields for epistemic transparency.
    """
    if model is None:
        return True, "No model to check (vacuously valid)"

    try:
        d = model.to_dict()
    except Exception as exc:
        return False, f"AX57 VIOLATION: to_dict() failed: {exc}"

    required_keys = {
        "name", "units", "fidelity_pairs", "isomorphism_results",
        "composition_mode", "all_seeds_omnipresent", "all_fidelities_valid",
        "celal_included", "tesanud_strength",
    }
    missing = required_keys - set(d.keys())
    if missing:
        return False, f"AX57 VIOLATION: missing keys in to_dict(): {missing}"

    return True, f"Model fully inspectable ({len(d)} keys)"


# ---------------------------------------------------------------------------
# Aggregate verification
# ---------------------------------------------------------------------------

def verify_all(
    model: Optional[HolographicModel] = None,
) -> Dict[str, Tuple[bool, str]]:
    """Run all 9 verification checks and return results.

    Returns a dict mapping check name to (passed, detail) tuple.
    """
    return {
        "seed_structure": check_seed_structure(model),
        "holographic_isomorphism": check_holographic_isomorphism(model),
        "seed_omnipresence": check_seed_omnipresence(model),
        "fidelity_bounds": check_fidelity_bounds(model),
        "celal_inclusion": check_celal_inclusion(model),
        "convergence_bound": check_convergence_bound(model),
        "tesanud_infirad": check_tesanud_infirad(model),
        "independence": check_independence(model),
        "transparency": check_transparency(model),
    }


# ---------------------------------------------------------------------------
# Convergence score (yakinlasma)
# ---------------------------------------------------------------------------

def yakinlasma(model: Optional[HolographicModel] = None) -> float:
    """Compute convergence score for a holographic model.

    Weighted composite of the 9 verification checks:
      seed_structure:             0.10
      holographic_isomorphism:    0.20   (AX37 — core axiom for this lens)
      seed_omnipresence:          0.15   (KV₆ — core kavaid for this lens)
      fidelity_bounds:            0.10   (T14)
      celal_inclusion:            0.10   (N-2/AX59)
      convergence_bound:          0.05   (KV₄/T6)
      tesanud_infirad:            0.10   (AX63)
      independence:               0.10   (KV₇)
      transparency:               0.10   (AX57)

    Returns a score in [0, 1) per T6/KV₄.
    """
    if model is None:
        return 0.0  # No data → no score (consistent with all other lenses)

    weights = {
        "seed_structure": 0.10,
        "holographic_isomorphism": 0.20,
        "seed_omnipresence": 0.15,
        "fidelity_bounds": 0.10,
        "celal_inclusion": 0.10,
        "convergence_bound": 0.05,
        "tesanud_infirad": 0.10,
        "independence": 0.10,
        "transparency": 0.10,
    }

    results = verify_all(model)
    score = sum(
        weights[k] * (1.0 if passed else 0.0)
        for k, (passed, _) in results.items()
    )
    return clamp_score(score)


# ---------------------------------------------------------------------------
# Framework summary (AX57 transparency)
# ---------------------------------------------------------------------------

def framework_summary() -> dict:
    """Return metadata about this lens for AX57 disclosure.

    Provides the lens name, number, faculty, domain, checked axioms and
    kavaid, capabilities, and the structural maximum score.
    """
    return {
        "lens": "Topoloji + Holografik",
        "lens_number": 7,
        "faculty": "Ruh + Hafî",
        "domain": "Topological/holographic analysis, B01–B22 dimensions",
        "axioms_checked": ["AX37", "AX38", "AX52", "AX59", "AX63"],
        "kavaid_checked": ["KV4", "KV6", "KV7"],
        "capabilities": [
            "22-dimensional holographic seed analysis (B01–B22)",
            "Holographic isomorphism detection (AX37, T12)",
            "Seed omnipresence verification (KV₆)",
            "Fidelity chain computation (T14)",
            "Celâl inclusion enforcement (N-2/AX59)",
            "Tesanüd/İnfirâd composition (AX63)",
            "Topological continuity verification",
        ],
        "max_score": 0.9999,
    }
