"""Vorjahr (previous-year) comparison service.

Provides aggregated previous-year data for Sheet 1's year-over-year columns.
Uses the yearly_summary table as a cache — if summary rows exist for the
previous year they are aggregated directly; otherwise the live cases table
is queried and the results are stored for future lookups.
"""

from __future__ import annotations

import logging

from sqlalchemy.orm import Session

from app.models.report import YearlySummary
from app.services.report_service import (
    FALLGRUPPEN,
    calculate_sheet1_data,
    calculate_sheet2_data,
    calculate_sheet3_data,
    calculate_sheet4_data,
)

logger = logging.getLogger(__name__)


# ---------------------------------------------------------------------------
# Public API
# ---------------------------------------------------------------------------

def get_vorjahr_summary(db: Session, jahr: int) -> dict:
    """Get previous year's aggregated data for comparison.

    First checks the ``yearly_summary`` table (cached per-KW rows).
    If no cached data exists, calculates live from the cases table and
    persists the results for future use.

    Returns::

        {
            "jahr": int,
            "erstberatungen": int,
            "ablehnungen": int,
            "unterlagen": int,
            "keine_rueckmeldung": int,
            "gutachten": int,
            "gutachten_alternative": int,
            "gutachten_bestaetigung": int,
        }
    """
    vorjahr = jahr - 1

    summaries = (
        db.query(YearlySummary)
        .filter(YearlySummary.jahr == vorjahr)
        .all()
    )

    if summaries:
        logger.debug("Vorjahr %d: using %d cached summary rows", vorjahr, len(summaries))
        return _aggregate_summaries(vorjahr, summaries)

    # No cache — calculate live and store
    logger.info("Vorjahr %d: no cache, calculating from cases table", vorjahr)
    return _calculate_and_cache(db, vorjahr)


def get_vorjahr_detail(db: Session, jahr: int) -> dict:
    """Get previous year's full breakdown (all sheets) for side-by-side comparison.

    This always calculates live from the cases table (no caching of detail data).

    Returns the same structure as ``generate_full_report`` but for *jahr - 1*.
    """
    vorjahr = jahr - 1
    from app.services.report_service import generate_full_report
    return generate_full_report(db, vorjahr)


def refresh_vorjahr_cache(db: Session, jahr: int) -> int:
    """Recalculate and store yearly summary rows for the given year.

    This is useful after historical data has been imported or corrected.
    Returns the number of KW rows written.
    """
    logger.info("Refreshing yearly summary cache for jahr=%d", jahr)

    # Delete existing cache rows for this year
    db.query(YearlySummary).filter(YearlySummary.jahr == jahr).delete()
    db.flush()

    return _store_summaries(db, jahr)


# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------

def _aggregate_summaries(jahr: int, summaries: list[YearlySummary]) -> dict:
    """Sum up weekly YearlySummary rows into yearly totals.

    Returns a dict with a ``summary`` key so that excel_export can access
    it the same way as the current-year sheet1 data (``data.get("summary")``).
    """
    totals = {
        "erstberatungen": sum(_safe(s.erstberatungen) for s in summaries),
        "ablehnungen": sum(_safe(s.ablehnungen) for s in summaries),
        "unterlagen": sum(_safe(s.unterlagen) for s in summaries),
        "keine_rueckmeldung": sum(_safe(s.keine_rueckmeldung) for s in summaries),
        "gutachten": sum(_safe(s.gutachten_gesamt) for s in summaries),
        "gutachten_alternative": sum(_safe(s.gutachten_alternative) for s in summaries),
        "gutachten_bestaetigung": sum(_safe(s.gutachten_bestaetigung) for s in summaries),
    }
    return {"jahr": jahr, "summary": totals}


def _calculate_and_cache(db: Session, jahr: int) -> dict:
    """Calculate from cases, store in yearly_summary, return aggregated."""
    written = _store_summaries(db, jahr)
    logger.info("Cached %d KW rows for jahr=%d", written, jahr)

    # Re-read from cache to return consistent data
    summaries = (
        db.query(YearlySummary)
        .filter(YearlySummary.jahr == jahr)
        .all()
    )
    return _aggregate_summaries(jahr, summaries)


def _store_summaries(db: Session, jahr: int) -> int:
    """Calculate all sheet data and store one YearlySummary row per KW.

    Returns number of KW rows written.
    """
    sheet1 = calculate_sheet1_data(db, jahr)
    sheet2 = calculate_sheet2_data(db, jahr)
    sheet3 = calculate_sheet3_data(db, jahr)
    sheet4 = calculate_sheet4_data(db, jahr)

    written = 0
    for i, s1_week in enumerate(sheet1["weekly"]):
        kw = s1_week["kw"]
        s2_week = sheet2["weekly"][i]
        s3_week = sheet3["weekly"][i]
        s4_week = sheet4["weekly"][i]

        # Skip KWs with zero data everywhere (no need to store empty rows)
        if s1_week["erstberatungen"] == 0 and s1_week["gutachten"] == 0:
            continue

        summary = YearlySummary(
            jahr=jahr,
            kw=kw,
            # Sheet 1 totals
            erstberatungen=s1_week["erstberatungen"],
            ablehnungen=s1_week["ablehnungen"],
            unterlagen=s1_week["unterlagen"],
            keine_rueckmeldung=s1_week["keine_rm"],
            gutachten_gesamt=s1_week["gutachten"],
            # Sheet 3 gesamt
            gutachten_alternative=s3_week["gesamt"]["alternative"],
            gutachten_bestaetigung=s3_week["gesamt"]["bestaetigung"],
            # Sheet 2: per-Fallgruppe
            onko_anzahl=s2_week["onko"]["anzahl"],
            onko_gutachten=s2_week["onko"]["gutachten"],
            onko_keine_rm=s2_week["onko"]["keine_rm"],
            kardio_anzahl=s2_week["kardio"]["anzahl"],
            kardio_gutachten=s2_week["kardio"]["gutachten"],
            kardio_keine_rm=s2_week["kardio"]["keine_rm"],
            intensiv_anzahl=s2_week["intensiv"]["anzahl"],
            intensiv_gutachten=s2_week["intensiv"]["gutachten"],
            intensiv_keine_rm=s2_week["intensiv"]["keine_rm"],
            galle_anzahl=s2_week["galle"]["anzahl"],
            galle_gutachten=s2_week["galle"]["gutachten"],
            galle_keine_rm=s2_week["galle"]["keine_rm"],
            sd_anzahl=s2_week["sd"]["anzahl"],
            sd_gutachten=s2_week["sd"]["gutachten"],
            sd_keine_rm=s2_week["sd"]["keine_rm"],
            # Sheet 3: per-Fallgruppe gutachten types
            onko_alternative=s3_week["onko"]["alternative"],
            onko_bestaetigung=s3_week["onko"]["bestaetigung"],
            kardio_alternative=s3_week["kardio"]["alternative"],
            kardio_bestaetigung=s3_week["kardio"]["bestaetigung"],
            intensiv_alternative=s3_week["intensiv"]["alternative"],
            intensiv_bestaetigung=s3_week["intensiv"]["bestaetigung"],
            galle_alternative=s3_week["galle"]["alternative"],
            galle_bestaetigung=s3_week["galle"]["bestaetigung"],
            sd_alternative=s3_week["sd"]["alternative"],
            sd_bestaetigung=s3_week["sd"]["bestaetigung"],
            # Sheet 4: therapy changes
            ta_ja=s4_week["ta_ja"],
            ta_nein=s4_week["ta_nein"],
            ta_diagnosekorrektur=s4_week["diagnosekorrektur"],
            ta_unterversorgung=s4_week["unterversorgung"],
            ta_uebertherapie=s4_week["uebertherapie"],
        )
        db.add(summary)
        written += 1

    db.commit()
    return written


def _safe(val) -> int:
    """Coerce None to 0."""
    return val if val is not None else 0
