"""
bileshke/quality.py — Quality Framework Implementation (Q-1 through Q-4).

AX51: Every instrument output MUST be evaluated by the Quality Framework.
      Quality measures WHAT KIND (modality), not just HOW MUCH (quantity).

Components:
  Q-1 (Coverage Gates):    AX52 multiplicative, AX55 dual gate
  Q-2 (Epistemic Scale):   AX56 max = İlmelyakîn
  Q-3 (Kavaid Register):   KV₁–KV₈ all must pass
  Q-4 (Completeness):      T17 max = 6/7, T18 per-module, AX57 transparency
"""

from __future__ import annotations

from typing import Any, Dict, List, Optional, Tuple

from bileshke.types import (
    EpistemicGrade,
    FunnelDiagnostic,
    Latife,
    LatifeVektor,
    LensId,
    LensResult,
    LENS_ORDER,
    LENS_PACKAGE,
    LENS_TO_LATIFE,
    MAX_COMPLETENESS_RATIO,
    NUM_LATIFELER,
    NUM_LENSES,
    NUM_ORTAM,
    Ortam,
    OrtamVektor,
    QualityReport,
    TESCIL,
    clamp_score,
)


# ========================================================================
# Kavaid identifiers (Q-3)
# ========================================================================

ALL_KAVAID = ("KV1", "KV2", "KV3", "KV4", "KV5", "KV6", "KV7", "KV8")

KAVAID_DESCRIPTIONS: Dict[str, str] = {
    "KV1": "Mana-yı Harfî / İsmî dual classification",
    "KV2": "Privation ontology of evil",
    "KV3": "Observer non-interference (şart-ı âdî)",
    "KV4": "Ne ayn ne gayr convergence bound (0 < C < 1)",
    "KV5": "Temsil → Hakikat functor verification",
    "KV6": "Holographic seed omnipresence",
    "KV7": "İhlâs / independence (no shared state)",
    "KV8": "Hakikat-i eşya = Esmâ grounding",
}


# ========================================================================
# Q-1: Coverage Gates
# ========================================================================

def compute_q1_coverage(
    latife: LatifeVektor,
    ortam: OrtamVektor,
) -> Dict[str, Any]:
    """
    Q-1: Coverage Gates — AX52 multiplicative, AX55 dual.

    Returns coverage analysis including:
      - latife gate (AX52 on 6 accessible latifeler)
      - ortam gate (AX52 on 3 ortam)
      - practical gate (AX55: both must pass)
      - per-latife status
      - per-ortam status
    """
    latife_gate = latife.gate_score()
    ortam_gate = ortam.gate_score()
    practical_gate = latife_gate * ortam_gate

    return {
        "component": "Q-1",
        "description": "Coverage Gates (AX52 multiplicative, AX55 dual)",
        "latife_gate": latife_gate,
        "ortam_gate": ortam_gate,
        "practical_gate": practical_gate,
        "latife_active": latife.active_count,
        "latife_max": 6,  # T17
        "latife_details": latife.to_dict(),
        "ortam_active": ortam.active_count,
        "ortam_max": NUM_ORTAM,
        "ortam_details": ortam.to_dict(),
        "passed": practical_gate > 0.0,
    }


# ========================================================================
# Q-2: Epistemic Degree Scale
# ========================================================================

def compute_q2_epistemic(
    results: List[LensResult],
) -> Dict[str, Any]:
    """
    Q-2: Epistemic Degree Scale — AX56 max = İlmelyakîn.

    Evaluates the epistemic grade claimed by each lens
    and the aggregate grade (minimum across all).
    """
    if not results:
        return {
            "component": "Q-2",
            "description": "Epistemic Degree Scale (AX56)",
            "aggregate_grade": EpistemicGrade.TASAVVUR.value,
            "per_lens": {},
            "max_achievable": EpistemicGrade.ILMELYAKIN.value,
            "hakkalyakin_accessible": False,
            "passed": True,
        }

    per_lens = {}
    min_grade = EpistemicGrade.ILMELYAKIN
    violations = []

    for r in results:
        per_lens[r.lens_id.value] = r.grade.value
        if r.grade < min_grade:
            min_grade = r.grade
        # AX56 check
        if r.grade == EpistemicGrade.HAKKALYAKIN:
            violations.append(r.lens_id.value)

    return {
        "component": "Q-2",
        "description": "Epistemic Degree Scale (AX56)",
        "aggregate_grade": min_grade.value,
        "per_lens": per_lens,
        "max_achievable": EpistemicGrade.ILMELYAKIN.value,
        "hakkalyakin_accessible": False,
        "violations": violations,
        "passed": len(violations) == 0,
    }


# ========================================================================
# Q-3: Kavaid Register
# ========================================================================

def compute_q3_kavaid(
    kavaid_checks: Optional[Dict[str, bool]] = None,
    composite_score: float = 0.0,
    latife: Optional[LatifeVektor] = None,
    funnel_diagnostic: Optional[FunnelDiagnostic] = None,
) -> Dict[str, Any]:
    """
    Q-3: Kavaid Register — all 8 kavaid must be satisfied.
    AX52: per-kavaid is multiplicative (one failure = total failure).

    If kavaid_checks is not provided, performs structural checks only:
      KV₄: composite < 0.95
      KV₇: structural (bileshke doesn't import lenses) +
           empirical (funnel diagnostic if available)

    If funnel_diagnostic is provided, KV₇ uses the empirical
    pairwise independence analysis from the fidelity funnel.
    This upgrades KV₇ from assertion to measurement.
    """
    checks: Dict[str, bool] = {}

    if kavaid_checks:
        checks.update(kavaid_checks)

    # Always verify KV₄ structurally
    if "KV4" not in checks:
        checks["KV4"] = composite_score < 0.95

    # KV₇: Independence verification
    # Level 1 (structural): bileshke doesn't import any lens package
    # Level 2 (empirical): funnel diagnostic if available
    if "KV7" not in checks:
        if funnel_diagnostic is not None:
            # Empirical KV₇: use actual pairwise independence measurement
            checks["KV7"] = funnel_diagnostic.kv7_satisfied
        else:
            # Structural KV₇ only: no lens imports (always true here)
            checks["KV7"] = True

    all_pass = all(checks.values()) if checks else True

    result: Dict[str, Any] = {
        "component": "Q-3",
        "description": "Kavaid Register (KV₁–KV₈, multiplicative per AX52)",
        "checks": checks,
        "all_pass": all_pass,
        "total_checked": len(checks),
        "total_required": len(ALL_KAVAID),
        "descriptions": {
            k: KAVAID_DESCRIPTIONS.get(k, "") for k in checks
        },
        "passed": all_pass,
    }

    # Attach funnel diagnostic detail if available
    if funnel_diagnostic is not None:
        result["kv7_method"] = "empirical (fidelity funnel)"
        result["kv7_max_ratio"] = funnel_diagnostic.max_correlation_ratio
        result["kv7_n_analyses"] = funnel_diagnostic.n_analyses
    else:
        result["kv7_method"] = "structural (no lens imports)"

    return result


# ========================================================================
# Q-4: Completeness and Transparency
# ========================================================================

def compute_q4_completeness(
    latife: LatifeVektor,
    results: List[LensResult],
) -> Dict[str, Any]:
    """
    Q-4: Completeness and Transparency — T17, T18, AX57.

    T17:  max completeness = 6/7 (Ahfâ permanently unmapped)
    T18:  Per-module diagnostic: b ∈ {0,1}⁷, max = 6
    AX57: Every output MUST include transparency statement
    """
    # T18: Per-module diagnostic
    per_module: Dict[str, Dict] = {}
    for r in results:
        latifeler = LENS_TO_LATIFE.get(r.lens_id, ())
        per_module[r.lens_id.value] = {
            "score": r.clamped_score,
            "grade": r.grade.value,
            "latifeler": [l.value for l in latifeler],
            "checks": f"{r.checks_passed}/{r.checks_total}" if r.checks_total > 0 else "N/A",
        }

    # T17 completeness
    completeness = latife.completeness
    active = latife.active_count

    return {
        "component": "Q-4",
        "description": "Completeness and Transparency (T17, T18, AX57)",
        "completeness": completeness,
        "max_completeness": MAX_COMPLETENESS_RATIO,
        "latife_active": active,
        "latife_total": NUM_LATIFELER,
        "ahfa_mapped": False,  # AX53: always False
        "per_module": per_module,
        "lenses_active": len(results),
        "lenses_total": NUM_LENSES,
        "passed": True,  # Q-4 is informational, not gating
    }


# ========================================================================
# Full Quality Assessment
# ========================================================================

def build_quality_report(
    results: List[LensResult],
    composite_score: float,
    latife: LatifeVektor,
    ortam: OrtamVektor,
    kavaid_checks: Optional[Dict[str, bool]] = None,
) -> Dict[str, Any]:
    """
    Build the complete 4-component quality assessment.

    Returns a dict containing Q-1 through Q-4 evaluations
    plus the overall quality verdict.
    """
    q1 = compute_q1_coverage(latife, ortam)
    q2 = compute_q2_epistemic(results)
    q3 = compute_q3_kavaid(kavaid_checks, composite_score, latife)
    q4 = compute_q4_completeness(latife, results)

    all_pass = q1["passed"] and q2["passed"] and q3["passed"]

    return {
        "quality_framework": "AX51",
        "Q1_coverage": q1,
        "Q2_epistemic": q2,
        "Q3_kavaid": q3,
        "Q4_completeness": q4,
        "overall_pass": all_pass,
        "composite_score": clamp_score(composite_score),
    }


# ========================================================================
# Framework summary (AX57 disclosure)
# ========================================================================

def framework_summary() -> Dict[str, Any]:
    """
    AX57 transparency: bileshke engine metadata.
    """
    return {
        "engine": "Bileshke (Composite Convergence)",
        "phase": "D",
        "formula": "bileshke(t) = Σᵢ wᵢ · yakinlasma(mᵢ, t)",
        "constraints": [
            "Σwᵢ = 1",
            "composite ∈ [0, 1) (T6/KV₄)",
            "composite ≥ 0.95 → KV₄ warning",
            "AX52: multiplicative gate",
            "AX53: Ahfâ permanently unmapped",
            "AX55: dual coverage gate",
            "AX56: max grade = İlmelyakîn",
            "T17: max completeness = 6/7",
        ],
        "quality_components": ["Q-1 Coverage", "Q-2 Epistemic", "Q-3 Kavaid", "Q-4 Completeness"],
        "axioms_implemented": [
            "AX49", "AX50", "AX51", "AX52", "AX53",
            "AX54", "AX55", "AX56",
        ],
        "theorems_implemented": ["T6", "T17", "T18"],
        "kavaid_checked": list(ALL_KAVAID),
        "tescil_mapping": {
            l.value: (TESCIL[l].value if TESCIL[l] else "∅")
            for l in Latife
        },
        "lens_order": [l.value for l in LENS_ORDER],
        "max_score": 0.9999,
    }
