"""Wahlprogramm-Referenzsystem mit Zitaten und Seitenreferenzen.

Bundesland-bewusst seit Issue #5: ``WAHLPROGRAMME[bundesland][partei]`` statt
flach. Konsumiert ``BUNDESLAENDER`` aus ``bundeslaender.py`` für die
Regierungsfraktionen-Lookup und für Plausibilitätsprüfungen.

Verantwortlich für die schlüsselwortbasierte Fallback-Suche in den
paged-Textversionen der Wahlprogramme. Die semantische Suche lebt in
``embeddings.py``.
"""

import re
from pathlib import Path
from typing import Optional

from .bundeslaender import BUNDESLAENDER


# WAHLPROGRAMME[bundesland][partei] -> Metadaten
# Beim Hinzufügen eines neuen Bundeslands: Eintrag hier UND parallel
# in WAHLPROGRAMM_KONTEXT_FILES.
WAHLPROGRAMME: dict[str, dict[str, dict]] = {
    "NRW": {
        "CDU": {
            "file": "cdu-nrw-2022.pdf",
            "titel": "Machen, worauf es ankommt",
            "partei": "CDU NRW",
            "jahr": 2022,
            "seiten": 109,
        },
        "SPD": {
            "file": "spd-nrw-2022.pdf",
            "titel": "Unser Land von morgen",
            "partei": "SPD NRW",
            "jahr": 2022,
            "seiten": 116,
        },
        "GRÜNE": {
            "file": "gruene-nrw-2022.pdf",
            "titel": "Von hier an Zukunft",
            "partei": "BÜNDNIS 90/DIE GRÜNEN NRW",
            "jahr": 2022,
            "seiten": 100,
        },
        "FDP": {
            "file": "fdp-nrw-2022.pdf",
            "titel": "Nie gab es mehr zu tun",
            "partei": "FDP NRW",
            "jahr": 2022,
            "seiten": 96,
        },
        "AfD": {
            "file": "afd-nrw-2022.pdf",
            "titel": "Wer sonst.",
            "partei": "AfD NRW",
            "jahr": 2022,
            "seiten": 68,
        },
    },
    # Sachsen-Anhalt — Wahlprogramme zur LTW 06.06.2021. Die aktuelle 8. WP
    # (seit 07/2021) wird mit diesen Programmen analysiert.
    "LSA": {
        "CDU": {
            "file": "cdu-lsa-2021.pdf",
            "titel": "Unsere Heimat. Unsere Verantwortung.",
            "partei": "CDU Sachsen-Anhalt",
            "jahr": 2021,
            "seiten": 82,
        },
        "SPD": {
            "file": "spd-lsa-2021.pdf",
            "titel": "Zusammenhalt und neue Chancen. Politik fürs ganze Land",
            "partei": "SPD Sachsen-Anhalt",
            "jahr": 2021,
            "seiten": 77,
        },
        "GRÜNE": {
            "file": "gruene-lsa-2021.pdf",
            "titel": "Verlässlich für Sachsen-Anhalt",
            "partei": "BÜNDNIS 90/DIE GRÜNEN Sachsen-Anhalt",
            "jahr": 2021,
            "seiten": 164,
        },
        "FDP": {
            "file": "fdp-lsa-2021.pdf",
            "titel": "Wahlprogramm der FDP Sachsen-Anhalt zur Landtagswahl 2021",
            "partei": "FDP Sachsen-Anhalt",
            "jahr": 2021,
            "seiten": 76,
        },
        "AfD": {
            "file": "afd-lsa-2021.pdf",
            "titel": "Alles für unsere Heimat! Programm der AfD Sachsen-Anhalt zur Landtagswahl 2021",
            "partei": "AfD Sachsen-Anhalt",
            "jahr": 2021,
            "seiten": 64,
        },
        "LINKE": {
            "file": "linke-lsa-2021.pdf",
            "titel": "Wahlprogramm zur Landtagswahl 2021",
            "partei": "DIE LINKE Sachsen-Anhalt",
            "jahr": 2021,
            "seiten": 88,
        },
    },
    # Mecklenburg-Vorpommern — Wahlprogramme zur LTW 26.09.2021. Die
    # aktuelle 8. WP (seit 26.10.2021) wird mit diesen Programmen
    # analysiert. Issue #4.
    "MV": {
        "CDU": {
            "file": "cdu-mv-2021.pdf",
            "titel": "Zusammen. Den Blick nach vorn. Gemeinsam die Zukunft meistern",
            "partei": "CDU Mecklenburg-Vorpommern",
            "jahr": 2021,
            "seiten": 56,
        },
        "SPD": {
            "file": "spd-mv-2021.pdf",
            "titel": "Verantwortung für heute und morgen — Regierungsprogramm 2021–2026",
            "partei": "SPD Mecklenburg-Vorpommern",
            "jahr": 2021,
            "seiten": 95,
        },
        "GRÜNE": {
            "file": "gruene-mv-2021.pdf",
            "titel": "Für Klima, Land und ein besseres Miteinander",
            "partei": "BÜNDNIS 90/DIE GRÜNEN Mecklenburg-Vorpommern",
            "jahr": 2021,
            "seiten": 88,
        },
        "FDP": {
            "file": "fdp-mv-2021.pdf",
            "titel": "Wahlprogramm der Freien Demokraten Mecklenburg-Vorpommern zur Landtagswahl 2021",
            "partei": "FDP Mecklenburg-Vorpommern",
            "jahr": 2021,
            "seiten": 120,
        },
        "AfD": {
            "file": "afd-mv-2021.pdf",
            "titel": "Landeswahlprogramm der AfD Mecklenburg-Vorpommern 2021",
            "partei": "AfD Mecklenburg-Vorpommern",
            "jahr": 2021,
            "seiten": 84,
        },
        "LINKE": {
            "file": "linke-mv-2021.pdf",
            "titel": "Das ist links! — Zukunftsprogramm für Mecklenburg-Vorpommern",
            "partei": "DIE LINKE Mecklenburg-Vorpommern",
            "jahr": 2021,
            "seiten": 82,
        },
    },
    # Berlin — Wahlprogramme zur Abgeordnetenhauswahl 2021 (am 26.09.2021,
    # wiederholt am 12.02.2023). Die laufende 19. WP (seit 27.04.2023) wird
    # mit den 2021er Programmen analysiert, weil die Parteien zur
    # Wiederholungswahl mit denselben Programmen angetreten sind. Issue #10.
    "BE": {
        "CDU": {
            "file": "cdu-be-2023.pdf",
            "titel": "Unser Berlin. Mehr geht nur gemeinsam. — Berlin-Plan der CDU Berlin 2021–2026",
            "partei": "CDU Berlin",
            "jahr": 2021,
            "seiten": 135,
        },
        "SPD": {
            "file": "spd-be-2023.pdf",
            "titel": "Ganz sicher Berlin — Wahlprogramm der SPD Berlin zur Abgeordnetenhauswahl 2021",
            "partei": "SPD Berlin",
            "jahr": 2021,
            "seiten": 86,
        },
        "GRÜNE": {
            "file": "gruene-be-2023.pdf",
            "titel": "Unser Plan für Berlin — Landeswahlprogramm BÜNDNIS 90/DIE GRÜNEN Berlin 2021",
            "partei": "BÜNDNIS 90/DIE GRÜNEN Berlin",
            "jahr": 2021,
            "seiten": 280,
        },
        "LINKE": {
            "file": "linke-be-2023.pdf",
            "titel": "rot. radikal. realistisch. — Unser Programm für die soziale Stadt",
            "partei": "DIE LINKE Berlin",
            "jahr": 2021,
            "seiten": 130,
        },
        "AfD": {
            "file": "afd-be-2023.pdf",
            "titel": "Wahlprogramm der AfD Berlin für die Wahl des Abgeordnetenhauses am 26. September 2021",
            "partei": "AfD Berlin",
            "jahr": 2021,
            "seiten": 166,
        },
    },
    # Thüringen — Wahlprogramme zur LTW 01.09.2024 (WP 8 seit 01.10.2024).
    # Brombeer-Koalition CDU+BSW+SPD als Minderheit. Issue #37.
    "TH": {
        "CDU": {"file": "cdu-th-2024.pdf", "titel": "Wahlprogramm der CDU Thüringen 2024", "partei": "CDU Thüringen", "jahr": 2024, "seiten": 83},
        "AfD": {"file": "afd-th-2024.pdf", "titel": "AfD Thüringen Landtagswahlprogramm 2024", "partei": "AfD Thüringen", "jahr": 2024, "seiten": 100},
        "LINKE": {"file": "linke-th-2024.pdf", "titel": "DIE LINKE Thüringen Wahlprogramm 2024", "partei": "DIE LINKE Thüringen", "jahr": 2024, "seiten": 100},
        "BSW": {"file": "bsw-th-2024.pdf", "titel": "BSW Thüringen Wahlprogramm 2024", "partei": "BSW Thüringen", "jahr": 2024, "seiten": 50},
        "SPD": {"file": "spd-th-2024.pdf", "titel": "SPD Thüringen Wahlprogramm 2024", "partei": "SPD Thüringen", "jahr": 2024, "seiten": 100},
    },
    # Brandenburg — Wahlprogramme zur LTW 22.09.2024 (WP 8 seit 23.10.2024).
    # Kabinett Woidke IV (SPD-BSW). Issue #39.
    "BB": {
        "SPD": {"file": "spd-bb-2024.pdf", "titel": "SPD Brandenburg Wahlprogramm 2024", "partei": "SPD Brandenburg", "jahr": 2024, "seiten": 100},
        "AfD": {"file": "afd-bb-2024.pdf", "titel": "AfD Brandenburg Wahlprogramm 2024", "partei": "AfD Brandenburg", "jahr": 2024, "seiten": 100},
        "CDU": {"file": "cdu-bb-2024.pdf", "titel": "CDU Brandenburg Wahlprogramm 2024", "partei": "CDU Brandenburg", "jahr": 2024, "seiten": 100},
        "BSW": {"file": "bsw-bb-2024.pdf", "titel": "BSW Brandenburg Wahlprogramm 2024", "partei": "BSW Brandenburg", "jahr": 2024, "seiten": 50},
    },
    # Hamburg — Wahlprogramme zur Bürgerschaftswahl 02.03.2025 (WP 23 seit 26.03.2025).
    # Senat Tschentscher III (SPD-GRÜNE). Issue #40.
    "HH": {
        "SPD": {"file": "spd-hh-2025.pdf", "titel": "SPD Hamburg Wahlprogramm Bürgerschaftswahl 2025", "partei": "SPD Hamburg", "jahr": 2025, "seiten": 100},
        "CDU": {"file": "cdu-hh-2025.pdf", "titel": "CDU Hamburg Wahlprogramm Bürgerschaftswahl 2025", "partei": "CDU Hamburg", "jahr": 2025, "seiten": 100},
        "GRÜNE": {"file": "gruene-hh-2025.pdf", "titel": "Gute Gründe für Grün — Regierungsprogramm BÜNDNIS 90/DIE GRÜNEN Hamburg 2025", "partei": "BÜNDNIS 90/DIE GRÜNEN Hamburg", "jahr": 2025, "seiten": 100},
        "LINKE": {"file": "linke-hh-2025.pdf", "titel": "DIE LINKE Hamburg Wahlprogramm Bürgerschaftswahl 2025", "partei": "DIE LINKE Hamburg", "jahr": 2025, "seiten": 100},
        "AfD": {"file": "afd-hh-2025.pdf", "titel": "AfD Hamburg Wahlprogramm Bürgerschaftswahl 2025", "partei": "AfD Hamburg", "jahr": 2025, "seiten": 100},
    },
    # Schleswig-Holstein — Wahlprogramme zur LTW 08.05.2022 (WP 20 seit 07.06.2022).
    # Kabinett Günther II (CDU-GRÜNE). Issue #32.
    "SH": {
        "CDU": {"file": "cdu-sh-2022.pdf", "titel": "CDU Schleswig-Holstein Wahlprogramm 2022", "partei": "CDU Schleswig-Holstein", "jahr": 2022, "seiten": 100},
        "SPD": {"file": "spd-sh-2022.pdf", "titel": "SPD Schleswig-Holstein Wahlprogramm 2022", "partei": "SPD Schleswig-Holstein", "jahr": 2022, "seiten": 100},
        "GRÜNE": {"file": "gruene-sh-2022.pdf", "titel": "BÜNDNIS 90/DIE GRÜNEN Schleswig-Holstein Wahlprogramm 2022", "partei": "BÜNDNIS 90/DIE GRÜNEN Schleswig-Holstein", "jahr": 2022, "seiten": 100},
        "FDP": {"file": "fdp-sh-2022.pdf", "titel": "FDP Schleswig-Holstein Wahlprogramm 2022", "partei": "FDP Schleswig-Holstein", "jahr": 2022, "seiten": 100},
        "SSW": {"file": "ssw-sh-2022.pdf", "titel": "SSW Schleswig-Holstein Wahlprogramm 2022", "partei": "SSW", "jahr": 2022, "seiten": 80},
    },
    # Baden-Württemberg — Wahlprogramme zur LTW 14.03.2021 (WP 17, läuft bis Konstituierung
    # des 18. Landtags nach 08.03.2026). Kabinett Kretschmann III (GRÜNE-CDU) noch
    # geschäftsführend. Issue #41.
    "BW": {
        "GRÜNE": {"file": "gruene-bw-2021.pdf", "titel": "Wachsen wir über uns hinaus — Landtagswahlprogramm BÜNDNIS 90/DIE GRÜNEN Baden-Württemberg 2021", "partei": "BÜNDNIS 90/DIE GRÜNEN Baden-Württemberg", "jahr": 2021, "seiten": 100},
        "CDU": {"file": "cdu-bw-2021.pdf", "titel": "Neue Ideen für eine neue Zeit — Regierungsprogramm der CDU Baden-Württemberg zur Landtagswahl 2021", "partei": "CDU Baden-Württemberg", "jahr": 2021, "seiten": 100},
        "AfD": {"file": "afd-bw-2021.pdf", "titel": "AfD Baden-Württemberg Landtagswahlprogramm 2021", "partei": "AfD Baden-Württemberg", "jahr": 2021, "seiten": 100},
        "SPD": {"file": "spd-bw-2021.pdf", "titel": "SPD Baden-Württemberg Wahlprogramm zur Landtagswahl 2021", "partei": "SPD Baden-Württemberg", "jahr": 2021, "seiten": 100},
        "FDP": {"file": "fdp-bw-2021.pdf", "titel": "FDP Baden-Württemberg Landtagswahlprogramm 2021", "partei": "FDP Baden-Württemberg", "jahr": 2021, "seiten": 100},
    },
    # Rheinland-Pfalz — Wahlprogramme zur LTW 14.03.2021 (WP 18, läuft bis Konstituierung
    # des 19. Landtags nach 22.03.2026). Kabinett Schweitzer I (SPD-GRÜNE-FDP) noch
    # geschäftsführend. Issue #42.
    "RP": {
        "SPD": {"file": "spd-rp-2021.pdf", "titel": "Wir mit Ihr — Regierungsprogramm der SPD Rheinland-Pfalz 2021–2026", "partei": "SPD Rheinland-Pfalz", "jahr": 2021, "seiten": 100},
        "CDU": {"file": "cdu-rp-2021.pdf", "titel": "Regierungsprogramm der CDU RLP 2021–26", "partei": "CDU Rheinland-Pfalz", "jahr": 2021, "seiten": 100},
        "AfD": {"file": "afd-rp-2021.pdf", "titel": "AfD Rheinland-Pfalz Wahlprogramm 2021", "partei": "AfD Rheinland-Pfalz", "jahr": 2021, "seiten": 100},
        "GRÜNE": {"file": "gruene-rp-2021.pdf", "titel": "BÜNDNIS 90/DIE GRÜNEN Rheinland-Pfalz Landtagswahlprogramm 2021", "partei": "BÜNDNIS 90/DIE GRÜNEN Rheinland-Pfalz", "jahr": 2021, "seiten": 100},
        "FREIE WÄHLER": {"file": "fw-rp-2021.pdf", "titel": "FREIE WÄHLER Rheinland-Pfalz Wahlprogramm 2021", "partei": "FREIE WÄHLER Rheinland-Pfalz", "jahr": 2021, "seiten": 80},
        "FDP": {"file": "fdp-rp-2021.pdf", "titel": "FDP Rheinland-Pfalz Landtagswahlprogramm 2021", "partei": "FDP Rheinland-Pfalz", "jahr": 2021, "seiten": 100},
    },
}

# Pro Bundesland: Markdown-Übersichtsdatei mit Wahlprogramm-Zusammenfassungen,
# wird als Kontext in den LLM-Prompt geladen (nicht für die Suche).
WAHLPROGRAMM_KONTEXT_FILES: dict[str, str] = {
    "NRW": "wahlprogramme-nrw-2022.md",
}

REFERENZEN_PATH = Path(__file__).parent / "static" / "referenzen"
KONTEXT_PATH = Path(__file__).parent / "kontext"


def get_wahlprogramm(bundesland: str, partei: str) -> Optional[dict]:
    """Liefert die Wahlprogramm-Metadaten oder None, wenn keins vorliegt."""
    return WAHLPROGRAMME.get(bundesland, {}).get(partei)


def parteien_mit_wahlprogramm(bundesland: str) -> list[str]:
    """Liste der Parteien, für die im gegebenen Bundesland ein Wahlprogramm vorliegt."""
    return list(WAHLPROGRAMME.get(bundesland, {}).keys())


def load_wahlprogramm_text(bundesland: str, partei: str) -> dict[int, str]:
    """Lädt Wahlprogramm-Text mit Seitenzuordnung.

    Returns:
        Dict mit Seitennummer -> Text. Leer, wenn kein Wahlprogramm hinterlegt
        oder die paged-Textdatei fehlt.
    """
    info = get_wahlprogramm(bundesland, partei)
    if not info:
        return {}

    # Versuche paged-Textdatei zu laden
    paged_file = KONTEXT_PATH / info['file'].replace('.pdf', '-paged.txt')
    if not paged_file.exists():
        # Fallback: Normale Textdatei
        txt_file = KONTEXT_PATH / info['file'].replace('.pdf', '.txt')
        if txt_file.exists():
            return {1: txt_file.read_text()}
        return {}

    text = paged_file.read_text()
    pages = {}
    current_page = 1
    current_text = []

    for line in text.split('\n'):
        if line.startswith('--- PAGE '):
            if current_text:
                pages[current_page] = '\n'.join(current_text)
            match = re.search(r'PAGE (\d+)', line)
            if match:
                current_page = int(match.group(1))
            current_text = []
        else:
            current_text.append(line)

    if current_text:
        pages[current_page] = '\n'.join(current_text)

    return pages


def search_wahlprogramm(
    bundesland: str,
    partei: str,
    keywords: list[str],
    max_results: int = 3,
) -> list[dict]:
    """Sucht relevante Passagen in einem Wahlprogramm.

    Args:
        bundesland: Bundesland-Code (NRW, LSA, …)
        partei: Partei-Kürzel (CDU, SPD, GRÜNE, FDP, AfD, …)
        keywords: Suchbegriffe
        max_results: Maximale Anzahl Ergebnisse

    Returns:
        Liste von {bundesland, partei, seite, text, score, url, quelle}
    """
    info = get_wahlprogramm(bundesland, partei)
    if not info:
        return []

    pages = load_wahlprogramm_text(bundesland, partei)
    if not pages:
        return []

    results = []
    keywords_lower = [k.lower() for k in keywords]

    for page_num, text in pages.items():
        text_lower = text.lower()
        score = sum(1 for kw in keywords_lower if kw in text_lower)

        if score > 0:
            paragraphs = text.split('\n\n')
            relevant_paragraphs = []

            for para in paragraphs:
                para_clean = para.strip()
                if len(para_clean) < 50:
                    continue
                para_lower = para_clean.lower()
                if any(kw in para_lower for kw in keywords_lower):
                    relevant_paragraphs.append(para_clean)

            if relevant_paragraphs:
                best_para = max(
                    relevant_paragraphs,
                    key=lambda p: sum(1 for kw in keywords_lower if kw in p.lower()),
                )
                if len(best_para) > 300:
                    best_para = best_para[:297] + "..."

                results.append({
                    "partei": partei,
                    "bundesland": bundesland,
                    "seite": page_num,
                    "text": best_para,
                    "score": score,
                    "url": f"/static/referenzen/{info['file']}#page={page_num}",
                    "quelle": f"{info['partei']} Wahlprogramm {info['jahr']}, S. {page_num}",
                })

    results.sort(key=lambda x: x['score'], reverse=True)
    return results[:max_results]


def find_relevant_quotes(
    antrag_text: str,
    fraktionen: list[str],
    bundesland: str,
) -> dict[str, list[dict]]:
    """Findet relevante Zitate aus Wahlprogrammen für einen Antrag.

    Args:
        antrag_text: Volltext des Antrags
        fraktionen: Liste der einreichenden Fraktionen
        bundesland: Bundesland-Code (Pflichtparameter; bestimmt, welche
            Wahlprogramme durchsucht werden und welche Regierungsfraktionen
            zusätzlich einbezogen werden).

    Returns:
        Dict mit Partei -> Liste von Zitaten
    """
    if bundesland not in BUNDESLAENDER:
        raise ValueError(f"Unbekanntes Bundesland: {bundesland}")

    # Extrahiere Keywords aus Antrag (einfache Heuristik)
    stopwords = {
        'der', 'die', 'das', 'und', 'oder', 'für', 'mit', 'von', 'zu', 'auf',
        'ist', 'sind', 'wird', 'werden', 'hat', 'haben', 'ein', 'eine', 'einer',
        'den', 'dem', 'des', 'im', 'in', 'an', 'bei', 'nach', 'über', 'unter',
        'durch', 'als', 'auch', 'nur', 'noch', 'aber', 'wenn', 'dass', 'sich',
        'nicht', 'wie', 'so', 'aus', 'zum', 'zur', 'vom', 'beim', 'seit', 'bis',
    }

    words = re.findall(r'\b[A-Za-zäöüÄÖÜß]{4,}\b', antrag_text)
    keywords = [w for w in words if w.lower() not in stopwords]

    word_freq: dict[str, int] = {}
    for w in keywords:
        w_lower = w.lower()
        word_freq[w_lower] = word_freq.get(w_lower, 0) + 1

    top_keywords = sorted(word_freq.keys(), key=lambda x: word_freq[x], reverse=True)[:15]

    # Antragsteller + Regierungsfraktionen des Bundeslands
    regierungsfraktionen = BUNDESLAENDER[bundesland].regierungsfraktionen
    parteien_to_search = set(fraktionen) | set(regierungsfraktionen)

    quotes: dict[str, list[dict]] = {}
    for partei in parteien_to_search:
        if get_wahlprogramm(bundesland, partei):
            found = search_wahlprogramm(bundesland, partei, top_keywords, max_results=2)
            if found:
                quotes[partei] = found

    return quotes


def format_quote_for_prompt(quotes: dict[str, list[dict]]) -> str:
    """Formatiert Zitate für den LLM-Prompt."""
    if not quotes:
        return ""

    lines = ["\n## Relevante Passagen aus Wahlprogrammen\n"]
    lines.append("Nutze diese Originalzitate als Belege in deiner Bewertung:\n")

    for partei, zitate in quotes.items():
        for z in zitate:
            lines.append(f"### {z['quelle']}")
            lines.append(f'> "{z["text"]}"')
            lines.append("")

    return "\n".join(lines)
