"""Discrepancy resolver — diagnose reconciliation issues and generate fixes.

Analyzes each discrepancy from a ReconciliationReport, classifies the root
cause, and generates SQL patches or Wright pipeline adjustments.
"""
from __future__ import annotations

from typing import Any, Dict, List, Optional

from .contracts import (
    CellReconciliation,
    DiscrepancyType,
    Fix,
    LogicArtifact,
    ReconciliationReport,
    ResolutionReport,
    RootCause,
)


class DiscrepancyResolver:
    """Diagnose reconciliation discrepancies and generate fixes."""

    def resolve(
        self,
        report: ReconciliationReport,
        artifacts: Optional[List[LogicArtifact]] = None,
    ) -> ResolutionReport:
        """Analyze each discrepancy, diagnose root cause, generate fix."""
        artifacts = artifacts or []
        fixes: List[Fix] = []

        discrepancy_cells = [
            c for c in report.cells
            if c.discrepancy_type != DiscrepancyType.MATCH
        ]

        for cell in discrepancy_cells:
            cause = self._diagnose(cell, artifacts)
            fix = self._generate_fix(cell, cause)
            fixes.append(fix)

        auto_fixable = sum(1 for f in fixes if f.fix_type != "manual_review")
        manual_review = sum(1 for f in fixes if f.fix_type == "manual_review")

        return ResolutionReport(
            reconciliation_id=report.report_id,
            total_discrepancies=len(discrepancy_cells),
            auto_fixable=auto_fixable,
            manual_review=manual_review,
            fixes=fixes,
            summary=(
                f"{len(discrepancy_cells)} discrepancies: "
                f"{auto_fixable} auto-fixable, {manual_review} need manual review."
            ),
        )

    # ------------------------------------------------------------------
    # Diagnosis
    # ------------------------------------------------------------------

    def _diagnose(
        self,
        cell: CellReconciliation,
        artifacts: List[LogicArtifact],
    ) -> RootCause:
        """Classify root cause: ROUNDING, FILTER_MISMATCH, FORMULA_DIFF,
        MISSING_DATA, TIMING, UNKNOWN."""
        disc = cell.discrepancy_type

        if disc == DiscrepancyType.ROUNDING:
            return RootCause.ROUNDING

        if disc in (DiscrepancyType.MISSING_EXCEL, DiscrepancyType.MISSING_WAREHOUSE):
            return RootCause.MISSING_DATA

        # GENUINE_DIFF — try to narrow it down
        if disc == DiscrepancyType.GENUINE_DIFF:
            # Check if any artifact mentions filter logic
            for art in artifacts:
                if art.objects and art.objects.filters:
                    return RootCause.FILTER_MISMATCH

            # Heuristic: large percentage difference hints at formula divergence
            if cell.excel_value is not None and cell.warehouse_value is not None:
                try:
                    ev = float(cell.excel_value)
                    wv = float(cell.warehouse_value)
                    if ev != 0 and abs((ev - wv) / ev) > 0.1:
                        return RootCause.FORMULA_DIFF
                except (ValueError, TypeError, ZeroDivisionError):
                    pass

            return RootCause.UNKNOWN

        return RootCause.UNKNOWN

    # ------------------------------------------------------------------
    # Fix generation
    # ------------------------------------------------------------------

    def _generate_fix(
        self,
        cell: CellReconciliation,
        cause: RootCause,
    ) -> Fix:
        """Generate SQL patch or Wright pipeline adjustment."""
        if cause == RootCause.ROUNDING:
            return Fix(
                root_cause=cause,
                description=f"Rounding difference at {cell.cell_address}: "
                            f"Excel={cell.excel_value}, Warehouse={cell.warehouse_value}",
                fix_type="sql_patch",
                sql=f"-- Apply ROUND() to align precision\n"
                    f"-- Column mapped to '{cell.mapping_label}'\n"
                    f"ROUND({cell.mapping_label}, 2)",
                confidence=0.9,
            )

        if cause == RootCause.FILTER_MISMATCH:
            return Fix(
                root_cause=cause,
                description=f"Filter mismatch at {cell.cell_address}: "
                            f"Excel={cell.excel_value}, Warehouse={cell.warehouse_value}. "
                            f"Check WHERE clause alignment.",
                fix_type="wright_adjustment",
                wright_object="VW_1",
                sql=f"-- Review filter predicates in VW_1 staging view\n"
                    f"-- Ensure warehouse filters match Excel SUMIFS criteria\n"
                    f"-- Column: {cell.mapping_label}",
                confidence=0.6,
            )

        if cause == RootCause.FORMULA_DIFF:
            return Fix(
                root_cause=cause,
                description=f"Formula divergence at {cell.cell_address}: "
                            f"Excel={cell.excel_value}, Warehouse={cell.warehouse_value}. "
                            f"Verify aggregation logic.",
                fix_type="wright_adjustment",
                wright_object="DT_2",
                sql=f"-- Check aggregation expression in DT_2\n"
                    f"-- Expected column: {cell.mapping_label}\n"
                    f"-- Excel value: {cell.excel_value}\n"
                    f"-- Warehouse value: {cell.warehouse_value}",
                confidence=0.5,
            )

        if cause == RootCause.MISSING_DATA:
            direction = (
                "warehouse" if cell.discrepancy_type == DiscrepancyType.MISSING_WAREHOUSE
                else "Excel"
            )
            return Fix(
                root_cause=cause,
                description=f"Data missing in {direction} for '{cell.mapping_label}'.",
                fix_type="manual_review",
                sql=f"-- Investigate missing data for '{cell.mapping_label}'\n"
                    f"-- Check source coverage in VW_1 staging view",
                confidence=0.3,
            )

        # TIMING or UNKNOWN
        return Fix(
            root_cause=cause,
            description=f"Unresolved discrepancy at {cell.cell_address}: "
                        f"Excel={cell.excel_value}, Warehouse={cell.warehouse_value}.",
            fix_type="manual_review",
            confidence=0.1,
        )
