#!/usr/bin/env python3
"""
ALLRIS Abstimmungs-Scraper für Antragstracker Hagen.
Lädt Abstimmungsergebnisse von to020-Seiten und extrahiert fraktionsweises Stimmverhalten.
"""

import argparse
import json
import os
import re
import sqlite3
import time
from pathlib import Path

import httpx
from bs4 import BeautifulSoup

PROJECT_ROOT = Path(__file__).resolve().parent.parent
DB_PATH = PROJECT_ROOT / "data" / "tracker_remote.db"

# DashScope API für Qwen
DASHSCOPE_URL = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions"
DASHSCOPE_KEY = os.environ.get("QWEN_API_KEY") or os.popen("security find-generic-password -s qwen-api -w 2>/dev/null").read().strip()


EXTRACTION_PROMPT = """Analysiere dieses Abstimmungsergebnis aus einem kommunalen Ratsinformationssystem.

TEXT:
{text}

---

Extrahiere das Stimmverhalten aller Fraktionen. Gib NUR valides JSON zurück:

{{
  "ergebnis": "beschlossen/abgelehnt/vertagt/zurückgezogen",
  "ergebnis_typ": "einstimmig/mehrheitlich/mit_gegenstimmen",
  "fraktionen": [
    {{"name": "SPD", "stimme": "ja", "anzahl": null, "bemerkung": null}},
    {{"name": "AfD", "stimme": "enthaltung", "anzahl": null, "bemerkung": null}},
    {{"name": "Hagen Aktiv", "stimme": "enthaltung", "anzahl": 1, "bemerkung": "1 Mitglied"}}
  ]
}}

Regeln:
- stimme: "ja", "nein", oder "enthaltung"
- anzahl: nur wenn explizit Teilmenge genannt ("1 Mitglied"), sonst null
- Bei "einstimmig" oder "ungeändert beschlossen" ohne Gegenstimmen: alle bekannten Fraktionen als "ja"
- Bekannte Hagener Fraktionen: SPD, CDU, Grüne, FDP, AfD, HAK/Die Linke, Hagen Aktiv, Freie Wähler

NUR JSON, keine Erklärungen."""


def get_db():
    conn = sqlite3.connect(str(DB_PATH))
    conn.row_factory = sqlite3.Row
    return conn


def fetch_to020_page(client: httpx.Client, tolfdnr: int) -> str | None:
    """Lädt die to020-Seite (Tagesordnungspunkt-Detail)."""
    url = f"https://allris.hagen.de/public/to020?TOLFDNR={tolfdnr}"
    try:
        resp = client.get(url, timeout=30, follow_redirects=True)
        resp.raise_for_status()
        return resp.text
    except Exception as e:
        print(f"    Fehler beim Laden von {url}: {e}")
        return None


def extract_abstimmung_text(html: str) -> tuple[str | None, str | None]:
    """Extrahiert Abstimmungsergebnis-Block aus HTML.
    Returns: (ergebnis_kurz, volltext)
    """
    soup = BeautifulSoup(html, 'html.parser')
    
    # Kurzform: "ungeändert beschlossen" etc.
    ergebnis_kurz = None
    beschluss_span = soup.find('span', id='toBeschlussart')
    if beschluss_span:
        ergebnis_kurz = beschluss_span.get_text(strip=True)
    
    # Volltext: Abstimmungsergebnis-Block
    volltext = None
    
    # Suche nach docPart mit "Abstimmungsergebnis"
    for div in soup.find_all('div', class_='docPart'):
        text = div.get_text()
        if 'Abstimmungsergebnis' in text or 'einstimmig' in text.lower() or 'Enthaltung' in text:
            volltext = text.strip()
            break
    
    # Fallback: Suche im Wortprotokoll nach Abstimmungsinfo
    if not volltext:
        for div in soup.find_all('div', class_='docPart'):
            text = div.get_text()
            if any(kw in text.lower() for kw in ['abstimmung', 'ja-stimm', 'nein-stimm', 'enthält sich', 'mehrheitlich', 'einstimmig']):
                volltext = text.strip()
                break
    
    return ergebnis_kurz, volltext


def call_qwen_turbo(prompt: str) -> dict | None:
    """Ruft Qwen-Turbo API auf (schnell & günstig)."""
    if not DASHSCOPE_KEY:
        print("  FEHLER: Kein QWEN_API_KEY gefunden")
        return None
    
    try:
        resp = httpx.post(
            DASHSCOPE_URL,
            headers={
                "Authorization": f"Bearer {DASHSCOPE_KEY}",
                "Content-Type": "application/json"
            },
            json={
                "model": "qwen-turbo-latest",
                "messages": [{"role": "user", "content": prompt}],
                "temperature": 0.1
            },
            timeout=30
        )
        resp.raise_for_status()
        
        content = resp.json()["choices"][0]["message"]["content"]
        
        # JSON extrahieren
        if "```json" in content:
            content = content.split("```json")[1].split("```")[0]
        elif "```" in content:
            content = content.split("```")[1].split("```")[0]
        
        return json.loads(content.strip())
        
    except json.JSONDecodeError as e:
        print(f"    JSON-Parse-Fehler: {e}")
        return None
    except Exception as e:
        print(f"    API-Fehler: {e}")
        return None


def get_tolfdnrs_from_vorlage(client: httpx.Client, volfdnr: int) -> list[tuple[int, str, str]]:
    """Extrahiert TOLFDNRs aus der vo020-Seite.
    Returns: List of (tolfdnr, datum, gremium_name)
    """
    url = f"https://allris.hagen.de/public/vo020?VOLFDNR={volfdnr}"
    try:
        resp = client.get(url, timeout=30, follow_redirects=True)
        resp.raise_for_status()
        html = resp.text
        
        results = []
        soup = BeautifulSoup(html, 'html.parser')
        
        # Suche nach Links zu to020
        for link in soup.find_all('a', href=re.compile(r'TOLFDNR=\d+')):
            match = re.search(r'TOLFDNR=(\d+)', link.get('href', ''))
            if match:
                tolfdnr = int(match.group(1))
                # Versuche Datum und Gremium aus Kontext zu extrahieren
                row = link.find_parent('tr')
                datum = ''
                gremium = ''
                if row:
                    cells = row.find_all('td')
                    for cell in cells:
                        text = cell.get_text(strip=True)
                        if re.match(r'\d{2}\.\d{2}\.\d{4}', text):
                            datum = text
                        elif 'Sitzung' in text or 'Rat' in text or 'Ausschuss' in text:
                            gremium = text
                results.append((tolfdnr, datum, gremium))
        
        return list(set(results))  # Deduplizieren
    except Exception as e:
        print(f"    Fehler beim Laden von vo020: {e}")
        return []


def process_vorlage(conn: sqlite3.Connection, client: httpx.Client, vorlage: dict) -> int:
    """Verarbeitet alle TOLFDNRs einer Vorlage.
    Returns: Anzahl erfolgreicher Abstimmungen
    """
    vid = vorlage['id']
    volfdnr = vorlage.get('volfdnr')
    
    if not volfdnr:
        # VOLFDNR aus web_url extrahieren
        web_url = vorlage.get('web_url', '')
        match = re.search(r'VOLFDNR=(\d+)', web_url)
        if match:
            volfdnr = int(match.group(1))
        else:
            return 0
    
    # TOLFDNRs von Vorlagen-Seite holen
    tolfdnrs = get_tolfdnrs_from_vorlage(client, volfdnr)
    if not tolfdnrs:
        return 0
    
    success = 0
    for tolfdnr, datum, gremium in tolfdnrs:
        # Prüfen ob schon verarbeitet
        existing = conn.execute(
            "SELECT id FROM abstimmungen WHERE vorlage_id = ? AND ergebnis_detail LIKE ?",
            (vid, f'%{tolfdnr}%')
        ).fetchone()
        if existing:
            continue
        
        if process_tolfdnr(conn, client, vid, tolfdnr, datum, gremium):
            success += 1
        time.sleep(0.3)
    
    return success


def process_tolfdnr(conn: sqlite3.Connection, client: httpx.Client, 
                    vorlage_id: int, tolfdnr: int, datum: str, gremium: str) -> bool:
    """Verarbeitet eine einzelne TOLFDNR."""
    
    # Seite laden
    html = fetch_to020_page(client, tolfdnr)
    if not html:
        return False
    
    # Abstimmungstext extrahieren
    ergebnis_kurz, volltext = extract_abstimmung_text(html)
    
    if not ergebnis_kurz and not volltext:
        return False
    
    # KI-Analyse wenn Volltext vorhanden
    fraktionen_data = []
    if volltext and len(volltext) > 20:
        prompt = EXTRACTION_PROMPT.format(text=volltext[:3000])
        result = call_qwen_turbo(prompt)
        if result and 'fraktionen' in result:
            fraktionen_data = result['fraktionen']
            if result.get('ergebnis'):
                ergebnis_kurz = result['ergebnis']
    
    # Gremium-ID finden
    gremium_id = None
    if gremium:
        row = conn.execute("SELECT id FROM gremien WHERE name LIKE ?", (f"%{gremium[:20]}%",)).fetchone()
        if row:
            gremium_id = row['id']
    
    # Datum parsen
    sitzung_datum = None
    if datum:
        try:
            parts = datum.split('.')
            if len(parts) == 3:
                sitzung_datum = f"{parts[2]}-{parts[1]}-{parts[0]}"
        except:
            pass
    
    # In DB speichern
    detail_json = json.dumps({
        "tolfdnr": tolfdnr,
        "fraktionen": fraktionen_data
    }, ensure_ascii=False) if fraktionen_data else json.dumps({"tolfdnr": tolfdnr})
    
    cursor = conn.execute("""
        INSERT INTO abstimmungen (beratung_id, vorlage_id, gremium_id, sitzung_datum, ergebnis, ergebnis_detail, volltext)
        VALUES (?, ?, ?, ?, ?, ?, ?)
    """, (None, vorlage_id, gremium_id, sitzung_datum, ergebnis_kurz, detail_json, volltext))
    
    abstimmung_id = cursor.lastrowid
    
    # Fraktionen speichern
    for f in fraktionen_data:
        conn.execute("""
            INSERT INTO abstimmungen_fraktionen (abstimmung_id, fraktion, stimme, anzahl, bemerkung)
            VALUES (?, ?, ?, ?, ?)
        """, (abstimmung_id, f.get('name'), f.get('stimme'), f.get('anzahl'), f.get('bemerkung')))
    
    conn.commit()
    
    print(f"  ✓ TOLFDNR {tolfdnr}: {ergebnis_kurz or 'OK'} ({len(fraktionen_data)} Fraktionen)")
    return True


def main():
    parser = argparse.ArgumentParser(description="ALLRIS Abstimmungs-Scraper")
    parser.add_argument("--limit", type=int, default=10, help="Max. Anzahl Vorlagen")
    parser.add_argument("--typ", type=str, default="antrag", help="Vorlagen-Typ (antrag/anfrage)")
    parser.add_argument("--vorlage", type=int, help="Nur bestimmte Vorlage-ID")
    args = parser.parse_args()
    
    print(f"=== ALLRIS Abstimmungs-Scraper ===\n")
    
    conn = get_db()
    client = httpx.Client()
    
    # Vorlagen mit web_url finden, die noch keine Abstimmung haben
    query = """
        SELECT v.id, v.aktenzeichen, v.web_url
        FROM vorlagen v
        LEFT JOIN abstimmungen a ON v.id = a.vorlage_id
        WHERE v.web_url IS NOT NULL
          AND a.id IS NULL
    """
    params = []
    
    if args.typ:
        query += " AND v.typ = ?"
        params.append(args.typ)
    
    if args.vorlage:
        query += " AND v.id = ?"
        params.append(args.vorlage)
    
    query += f" ORDER BY v.datum_eingang DESC LIMIT {args.limit}"
    
    vorlagen = conn.execute(query, params).fetchall()
    print(f"Verarbeite {len(vorlagen)} Vorlagen\n")
    
    total_success = 0
    for v in vorlagen:
        vd = dict(v)
        print(f"Vorlage {vd.get('aktenzeichen', vd['id'])}...")
        success = process_vorlage(conn, client, vd)
        total_success += success
        if success == 0:
            print(f"  (keine Abstimmungsdaten)")
        time.sleep(0.5)
    
    client.close()
    conn.close()
    
    print(f"\n=== Fertig: {total_success} Abstimmungen extrahiert ===")


if __name__ == "__main__":
    main()
