"""Cross-grain rollup validation."""
from __future__ import annotations

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

from .contracts import (
    CrossGrainStatus,
    CrossGrainValidation,
    GrainLevel,
    _new_id,
)
from .grain_analyzer import GrainAnalyzer

logger = logging.getLogger(__name__)


class CrossGrainValidator:
    """Verify rollup correctness when aggregating across grain levels.

    For each measure: SUM at fine grain, SUM at coarse grain → compare.
    Reports pass/fail/warn per measure × grain combination.
    """

    def __init__(self, threshold_pct: float = 0.01):
        self._threshold_pct = threshold_pct

    def validate(
        self,
        fact_table: str,
        fine_grain: GrainLevel,
        coarse_grain: GrainLevel,
        measure_totals: Dict[str, Dict[str, float]],
    ) -> List[CrossGrainValidation]:
        """Validate rollup correctness for a set of measures.

        Args:
            fact_table: Name of the fact table being validated
            fine_grain: The finer grain level
            coarse_grain: The coarser grain level
            measure_totals: {measure_name: {"fine": total, "coarse": total}}

        Returns:
            List of CrossGrainValidation results
        """
        if not GrainAnalyzer.is_finer(fine_grain, coarse_grain):
            logger.warning("fine_grain=%s is not finer than coarse_grain=%s", fine_grain, coarse_grain)

        results: List[CrossGrainValidation] = []
        for measure, totals in measure_totals.items():
            fine_total = totals.get("fine", 0.0)
            coarse_total = totals.get("coarse", 0.0)
            diff = abs(fine_total - coarse_total)
            diff_pct = diff / abs(fine_total) if fine_total != 0 else (0.0 if diff == 0 else 1.0)

            if diff_pct <= self._threshold_pct:
                status = CrossGrainStatus.PASS
            elif diff_pct <= self._threshold_pct * 5:
                status = CrossGrainStatus.WARN
            else:
                status = CrossGrainStatus.FAIL

            results.append(CrossGrainValidation(
                fact_table=fact_table,
                fine_grain=fine_grain,
                coarse_grain=coarse_grain,
                measure=measure,
                fine_total=fine_total,
                coarse_total=coarse_total,
                difference=diff,
                difference_pct=round(diff_pct, 6),
                status=status,
                threshold_pct=self._threshold_pct,
            ))

        return results

    def validate_from_queries(
        self,
        fact_table: str,
        fine_grain: GrainLevel,
        coarse_grain: GrainLevel,
        measures: List[str],
        fine_query_results: Dict[str, float],
        coarse_query_results: Dict[str, float],
    ) -> List[CrossGrainValidation]:
        """Validate using pre-executed query results."""
        measure_totals: Dict[str, Dict[str, float]] = {}
        for m in measures:
            measure_totals[m] = {
                "fine": fine_query_results.get(m, 0.0),
                "coarse": coarse_query_results.get(m, 0.0),
            }
        return self.validate(fact_table, fine_grain, coarse_grain, measure_totals)

    def generate_validation_sql(
        self,
        fact_table: str,
        measures: List[str],
        grain_column: str,
        schema_prefix: str = "",
    ) -> Dict[str, str]:
        """Generate SQL queries for cross-grain validation.

        Returns dict with keys: 'fine_query', 'coarse_query'
        """
        fq_table = f"{schema_prefix}{fact_table}" if schema_prefix else fact_table
        agg_exprs = ", ".join(f"SUM({m}) AS {m}" for m in measures)

        fine_sql = f"SELECT {agg_exprs} FROM {fq_table};"
        coarse_sql = f"SELECT {grain_column}, {agg_exprs} FROM {fq_table} GROUP BY {grain_column};"

        return {"fine_query": fine_sql, "coarse_query": coarse_sql}

    def summary(self, results: List[CrossGrainValidation]) -> Dict[str, Any]:
        """Summarize validation results."""
        total = len(results)
        passed = sum(1 for r in results if r.status == CrossGrainStatus.PASS)
        warned = sum(1 for r in results if r.status == CrossGrainStatus.WARN)
        failed = sum(1 for r in results if r.status == CrossGrainStatus.FAIL)
        max_diff = max((r.difference_pct for r in results), default=0.0)

        return {
            "total_validations": total,
            "passed": passed,
            "warnings": warned,
            "failed": failed,
            "pass_rate": round(passed / total, 4) if total else 0.0,
            "max_difference_pct": round(max_diff, 6),
            "overall_status": "pass" if failed == 0 and warned == 0 else ("warn" if failed == 0 else "fail"),
            "details": [r.model_dump() for r in results],
        }
