"""Status-Engine: computes chain status based on KONZEPT.md section 6."""

from __future__ import annotations

import sqlite3
from datetime import date, timedelta

# Threshold: a Vorlage is considered "old" after this many days without activity
VERSANDET_TAGE = 365


def compute_status(
    conn: sqlite3.Connection,
    ursprung_id: int,
    chain_typ: str,
    members: list[sqlite3.Row],
) -> dict:
    """Compute the overall status for a chain.

    Returns dict with keys: status, status_seit, vertagungen_count
    """
    if chain_typ == "anfrage":
        return _status_anfrage(conn, ursprung_id, members)
    elif chain_typ == "antrag":
        return _status_antrag(conn, ursprung_id, members)
    return {"status": "unbekannt", "status_seit": None, "vertagungen_count": 0}


def _status_anfrage(
    conn: sqlite3.Connection,
    ursprung_id: int,
    members: list[sqlite3.Row],
) -> dict:
    """Status logic for Anfragen (KONZEPT.md 6.1).

    angefragt:    Keine Stellungnahme, <1 Jahr
    beantwortet:  Stellungnahme + KI-Match >=0.7 + Kenntnisnahme
    offen:        Stellungnahme da, aber keine Kenntnisnahme
    abgewiegelt:  Stellungnahme + KI-Match <0.5
    versandet:    Keine Antwort, >1 Jahr
    zurückgezogen: Explizit zurückgezogen
    """
    heute = date.today()
    ursprung_datum = _parse_date(members[0]["datum_eingang"])

    # Check for Stellungnahme in chain members
    stellungnahmen = [m for m in members if m["typ"] == "stellungnahme"]
    has_stellungnahme = len(stellungnahmen) > 0

    # Check for Kenntnisnahme in Beratungen
    beratungen = conn.execute("""
        SELECT rolle, ergebnis, sitzung_datum
        FROM beratungen
        WHERE vorlage_id = ?
        ORDER BY sitzung_datum DESC
    """, (ursprung_id,)).fetchall()

    has_kenntnisnahme = any(
        b["rolle"] and "kenntnisnahme" in b["rolle"].lower()
        for b in beratungen
    )

    # Check KI-Match score for Antwort
    ki_score = _get_ki_score(conn, ursprung_id, "antwort_match")

    # Check zurückgezogen
    if _is_zurueckgezogen(beratungen):
        return {"status": "zurückgezogen", "status_seit": _latest_date(beratungen), "vertagungen_count": 0}

    if has_stellungnahme:
        if ki_score is not None and ki_score < 0.5:
            return {"status": "abgewiegelt", "status_seit": _vorlage_date(stellungnahmen[0]), "vertagungen_count": 0}
        if has_kenntnisnahme and (ki_score is None or ki_score >= 0.7):
            return {"status": "beantwortet", "status_seit": _vorlage_date(stellungnahmen[0]), "vertagungen_count": 0}
        return {"status": "offen", "status_seit": _vorlage_date(stellungnahmen[0]), "vertagungen_count": 0}

    # No Stellungnahme
    if ursprung_datum and (heute - ursprung_datum).days > VERSANDET_TAGE:
        return {"status": "versandet", "status_seit": ursprung_datum, "vertagungen_count": 0}

    return {"status": "angefragt", "status_seit": ursprung_datum, "vertagungen_count": 0}


def _status_antrag(
    conn: sqlite3.Connection,
    ursprung_id: int,
    members: list[sqlite3.Row],
) -> dict:
    """Status logic for Anträge (KONZEPT.md 6.2).

    eingereicht:           Neu, noch keine Beratung
    in_beratung:           Mindestens eine Beratung ohne Endbeschluss
    vertagt:               Letzte Beratung = vertagt
    verwiesen:             An anderen Ausschuss überwiesen
    beschlossen:           Angenommen, <1 Jahr, kein Umsetzungsbericht
    umgesetzt:             Umsetzungsbericht + KI-Match >=0.7
    teilweise_umgesetzt:   Umsetzungsbericht + KI-Match 0.4-0.7
    abgelehnt:             Beschluss = abgelehnt
    abgewiegelt:           Beschlossen + Bericht + KI-Match <0.4
    versandet:             Beschlossen, >1 Jahr, kein Bericht
    zurückgezogen:         Explizit zurückgezogen
    """
    heute = date.today()
    ursprung_datum = _parse_date(members[0]["datum_eingang"])

    beratungen = conn.execute("""
        SELECT rolle, ergebnis, sitzung_datum
        FROM beratungen
        WHERE vorlage_id = ?
        ORDER BY sitzung_datum DESC NULLS LAST
    """, (ursprung_id,)).fetchall()

    # Count Vertagungen
    vertagungen = sum(1 for b in beratungen if b["ergebnis"] and "vertagt" in b["ergebnis"].lower())

    # Check zurückgezogen
    if _is_zurueckgezogen(beratungen):
        return {"status": "zurückgezogen", "status_seit": _latest_date(beratungen), "vertagungen_count": vertagungen}

    # Check for Berichte in chain
    berichte = [m for m in members if m["typ"] == "bericht"]
    has_bericht = len(berichte) > 0

    # Determine beschluss from beratungen
    beschluss = _get_beschluss(beratungen)

    if beschluss == "abgelehnt":
        return {"status": "abgelehnt", "status_seit": _latest_date(beratungen), "vertagungen_count": vertagungen}

    if beschluss == "angenommen":
        beschluss_datum = _latest_date(beratungen)

        if has_bericht:
            ki_score = _get_ki_score(conn, ursprung_id, "umsetzung_match")
            bericht_datum = _vorlage_date(berichte[-1])

            if ki_score is not None:
                if ki_score >= 0.7:
                    return {"status": "umgesetzt", "status_seit": bericht_datum, "vertagungen_count": vertagungen}
                elif ki_score >= 0.4:
                    return {"status": "teilweise_umgesetzt", "status_seit": bericht_datum, "vertagungen_count": vertagungen}
                else:
                    return {"status": "abgewiegelt", "status_seit": bericht_datum, "vertagungen_count": vertagungen}
            return {"status": "umgesetzt", "status_seit": bericht_datum, "vertagungen_count": vertagungen}

        # Angenommen but no Bericht
        if beschluss_datum and (heute - beschluss_datum).days > VERSANDET_TAGE:
            return {"status": "versandet", "status_seit": beschluss_datum, "vertagungen_count": vertagungen}

        return {"status": "beschlossen", "status_seit": beschluss_datum, "vertagungen_count": vertagungen}

    if beschluss == "verwiesen":
        return {"status": "verwiesen", "status_seit": _latest_date(beratungen), "vertagungen_count": vertagungen}

    # No final decision yet
    if beratungen:
        last = beratungen[0]
        if last["ergebnis"] and "vertagt" in last["ergebnis"].lower():
            return {"status": "vertagt", "status_seit": _latest_date(beratungen), "vertagungen_count": vertagungen}
        return {"status": "in_beratung", "status_seit": _latest_date(beratungen), "vertagungen_count": vertagungen}

    # No beratungen at all
    return {"status": "eingereicht", "status_seit": ursprung_datum, "vertagungen_count": vertagungen}


# --- Helpers ---

def _parse_date(val: str | None) -> date | None:
    if not val:
        return None
    try:
        return date.fromisoformat(val)
    except (ValueError, TypeError):
        return None


def _vorlage_date(member: sqlite3.Row) -> date | None:
    return _parse_date(member["datum_eingang"])


def _latest_date(beratungen: list[sqlite3.Row]) -> date | None:
    dates = [_parse_date(b["sitzung_datum"]) for b in beratungen if b["sitzung_datum"]]
    return max(dates) if dates else None


def _get_ki_score(conn: sqlite3.Connection, vorlage_id: int, typ: str) -> float | None:
    row = conn.execute("""
        SELECT score FROM ki_bewertungen
        WHERE vorlage_id = ? AND typ = ?
        ORDER BY erstellt_at DESC
        LIMIT 1
    """, (vorlage_id, typ)).fetchone()
    return row["score"] if row else None


def _is_zurueckgezogen(beratungen: list[sqlite3.Row]) -> bool:
    return any(
        b["ergebnis"] and "zurückgezogen" in b["ergebnis"].lower()
        for b in beratungen
    )


def _get_beschluss(beratungen: list[sqlite3.Row]) -> str | None:
    """Determine the final decision from Beratungen.

    Looks for Entscheidung-role beratungen with a result.
    """
    for b in beratungen:
        ergebnis = (b["ergebnis"] or "").lower()
        rolle = (b["rolle"] or "").lower()

        if "abgelehnt" in ergebnis:
            return "abgelehnt"
        if "verwiesen" in ergebnis:
            return "verwiesen"
        if any(kw in ergebnis for kw in ("angenommen", "empfohlen", "beschlossen", "zugestimmt")):
            return "angenommen"
        # If rolle is Entscheidung and there's any ergebnis, it's likely a decision
        if "entscheidung" in rolle and ergebnis and "vertagt" not in ergebnis:
            return "angenommen"

    return None
