"""BAN YARO — Züchter-Datenexport (HTML + ODS)"""
import io
import zipfile
import logging
from datetime import date, datetime
from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import StreamingResponse

from database import db
from auth import get_current_user

router = APIRouter()
logger = logging.getLogger(__name__)


def _require_breeder(user=Depends(get_current_user)):
    if user["rolle"] not in ("breeder", "admin"):
        raise HTTPException(403, "Nur für Züchter.")
    return user


# ------------------------------------------------------------------
# Datenabruf
# ------------------------------------------------------------------
def _collect_data(user_id: int) -> dict:
    with db() as conn:
        profile = conn.execute(
            "SELECT bp.*, u.name AS user_name, u.email "
            "FROM breeder_profiles bp JOIN users u ON u.id = bp.user_id "
            "WHERE bp.user_id=?", (user_id,)
        ).fetchone()
        if not profile:
            return None

        bid = profile["id"]

        hunde = conn.execute(
            "SELECT * FROM zucht_hunde WHERE breeder_id=? ORDER BY name", (bid,)
        ).fetchall()

        hund_ids = [h["id"] for h in hunde]

        def rows_for(table, id_col):
            if not hund_ids:
                return []
            placeholders = ",".join("?" * len(hund_ids))
            return conn.execute(
                f"SELECT * FROM {table} WHERE {id_col} IN ({placeholders}) ORDER BY {id_col}",
                hund_ids
            ).fetchall()

        health  = rows_for("dog_health_tests",  "hund_id")
        genetic = rows_for("dog_genetic_tests", "hund_id")
        titles  = rows_for("dog_titles",        "hund_id")

        litters = conn.execute(
            "SELECT * FROM litters WHERE breeder_id=? ORDER BY created_at DESC", (bid,)
        ).fetchall()
        litter_ids = [l["id"] for l in litters]

        puppies, weights = [], []
        if litter_ids:
            placeholders = ",".join("?" * len(litter_ids))
            puppies = conn.execute(
                f"SELECT * FROM puppies WHERE wurf_id IN ({placeholders}) ORDER BY wurf_id",
                litter_ids
            ).fetchall()
            puppy_ids = [p["id"] for p in puppies]
            if puppy_ids:
                ph2 = ",".join("?" * len(puppy_ids))
                weights = conn.execute(
                    f"SELECT * FROM puppy_weights WHERE welpe_id IN ({ph2}) ORDER BY welpe_id, gemessen_am",
                    puppy_ids
                ).fetchall()

        # Stammbaum pro Hund (3 Generationen, flach)
        def pedigree_flat(hund_id, depth=3):
            if not hund_id or depth == 0:
                return {}
            row = conn.execute("SELECT id, name, zuchtbuchnummer, geburtsdatum FROM zucht_hunde WHERE id=?", (hund_id,)).fetchone()
            if not row:
                return {}
            result = {"name": row["name"], "nr": row["zuchtbuchnummer"] or "", "geb": row["geburtsdatum"] or ""}
            row2 = conn.execute("SELECT vater_id, mutter_id FROM zucht_hunde WHERE id=?", (hund_id,)).fetchone()
            if row2:
                result["vater"] = pedigree_flat(row2["vater_id"], depth - 1)
                result["mutter"] = pedigree_flat(row2["mutter_id"], depth - 1)
            return result

        pedigrees = {h["id"]: pedigree_flat(h["id"]) for h in hunde}

    return {
        "profile":  dict(profile),
        "hunde":    [dict(h) for h in hunde],
        "health":   [dict(r) for r in health],
        "genetic":  [dict(r) for r in genetic],
        "titles":   [dict(r) for r in titles],
        "litters":  [dict(l) for l in litters],
        "puppies":  [dict(p) for p in puppies],
        "weights":  [dict(w) for w in weights],
        "pedigrees": pedigrees,
    }


# ------------------------------------------------------------------
# HTML-Export
# ------------------------------------------------------------------
def _fmt_date(val):
    if not val:
        return "—"
    try:
        return datetime.strptime(str(val)[:10], "%Y-%m-%d").strftime("%d.%m.%Y")
    except Exception:
        return str(val)


def _health_badge(test_typ, ergebnis):
    color = "#6B7280"
    e = (ergebnis or "").upper()
    if test_typ == "HD":
        color = {"A1": "#16a34a", "A2": "#16a34a", "B1": "#86efac", "B2": "#86efac",
                 "C": "#eab308", "C1": "#eab308", "C2": "#eab308",
                 "D": "#f97316", "D1": "#f97316", "D2": "#f97316",
                 "E": "#dc2626", "E1": "#dc2626", "E2": "#dc2626"}.get(e, "#6B7280")
    elif test_typ == "ED":
        color = {"0": "#16a34a", "1": "#eab308", "2": "#f97316", "3": "#dc2626"}.get(e, "#6B7280")
    elif ergebnis in ("clear", "frei"):
        color = "#16a34a"
    elif ergebnis == "carrier":
        color = "#eab308"
    elif ergebnis == "affected":
        color = "#dc2626"
    return f'<span style="background:{color};color:#fff;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:600">{ergebnis}</span>'


def _pedigree_node_html(node, gen):
    if not node:
        return '<div style="background:#f3f4f6;border:1px dashed #d1d5db;border-radius:6px;padding:6px 8px;color:#9ca3af;font-size:11px;height:100%;box-sizing:border-box">Unbekannt</div>'
    geb = f"*{node['geb'][:4]}" if node.get("geb") else ""
    nr  = node.get("nr", "")
    bg  = "#7c3aed" if gen == 1 else ("#ede9fe" if gen == 2 else ("#f5f3ff" if gen == 3 else "#faf9ff"))
    col = "#fff" if gen == 1 else "#1f2937"
    return (
        f'<div style="background:{bg};color:{col};border-radius:6px;padding:6px 8px;'
        f'font-size:11px;height:100%;box-sizing:border-box;border:1px solid #e5e7eb">'
        f'<div style="font-weight:700;margin-bottom:2px">{node["name"]}</div>'
        + (f'<div style="opacity:.7">{nr}</div>' if nr else "")
        + (f'<div style="opacity:.7">{geb}</div>' if geb else "")
        + "</div>"
    )


def _pedigree_html(tree):
    # 4-Gen horizontaler Stammbaum als Tabelle
    def nodes(t, gen, max_gen=4):
        if gen > max_gen:
            return []
        item = [{"node": t, "gen": gen}]
        item += nodes(t.get("vater") if t else None, gen + 1, max_gen)
        item += nodes(t.get("mutter") if t else None, gen + 1, max_gen)
        return item

    rows = 8  # 2^3 für 4 Generationen
    cols = 4

    def collect(node, gen, row_start, row_span):
        if gen > cols:
            return []
        items = [{"node": node, "gen": gen, "row": row_start, "span": row_span}]
        half = row_span // 2
        items += collect(node.get("vater") if node else None, gen + 1, row_start, half)
        items += collect(node.get("mutter") if node else None, gen + 1, row_start + half, half)
        return items

    cells = collect(tree, 1, 0, rows)
    gen_labels = {1: "Proband", 2: "Eltern", 3: "Großeltern", 4: "Urgroßeltern"}

    # Grid als Tabelle (row_height = 50px)
    row_h = 52
    total_h = rows * row_h

    html = (
        f'<div style="overflow-x:auto;margin:12px 0">'
        f'<div style="display:grid;grid-template-columns:repeat({cols},1fr);'
        f'grid-template-rows:repeat({rows},{row_h}px);gap:4px;min-width:{cols*160}px">'
    )
    for c in cells:
        node, gen, row, span = c["node"], c["gen"], c["row"], c["span"]
        html += (
            f'<div style="grid-column:{gen};grid-row:{row+1}/span {span};padding:2px">'
            + _pedigree_node_html(node, gen)
            + "</div>"
        )
    html += "</div></div>"
    return html


def _generate_html(data: dict) -> str:
    p = data["profile"]
    today = date.today().strftime("%d.%m.%Y")

    hunde_html = ""
    for h in data["hunde"]:
        hid = h["id"]
        h_health  = [r for r in data["health"]  if r["hund_id"] == hid]
        h_genetic = [r for r in data["genetic"] if r["hund_id"] == hid]
        h_titles  = [r for r in data["titles"]  if r["hund_id"] == hid]
        tree = data["pedigrees"].get(hid, {})

        health_rows = "".join(
            f'<tr><td>{r["test_typ"]}</td><td>{_health_badge(r["test_typ"], r["ergebnis"])}</td>'
            f'<td>{_fmt_date(r["untersuch_am"])}</td><td>{r.get("labor","") or ""}</td>'
            f'<td>{r.get("untersucher","") or ""}</td></tr>'
            for r in h_health
        ) or "<tr><td colspan=5 style='color:#9ca3af'>Keine Einträge</td></tr>"

        genetic_rows = "".join(
            f'<tr><td>{r["marker_name"]}</td><td>{_health_badge("DNA", r["ergebnis_klasse"])}</td>'
            f'<td>{_fmt_date(r["getestet_am"])}</td><td>{r.get("labor","") or ""}</td></tr>'
            for r in h_genetic
        ) or "<tr><td colspan=4 style='color:#9ca3af'>Keine Einträge</td></tr>"

        title_rows = "".join(
            f'<tr><td><b>{r["titel_name"]}</b></td><td>{r["titel_typ"]}</td>'
            f'<td>{_fmt_date(r["verliehen_am"])}</td><td>{r.get("ort","") or ""}</td>'
            f'<td>{r.get("richter","") or ""}</td></tr>'
            for r in sorted(h_titles, key=lambda x: x["verliehen_am"] or "", reverse=True)
        ) or "<tr><td colspan=5 style='color:#9ca3af'>Keine Einträge</td></tr>"

        geschlecht = {"maennlich": "Rüde", "weiblich": "Hündin"}.get(h.get("geschlecht",""), "")

        hunde_html += f"""
        <div class="dog-card">
          <h2 style="color:#7c3aed;margin:0 0 4px">{h['name']}</h2>
          {f'<div style="color:#6b7280;margin-bottom:12px"><em>{h["rufname"]}</em></div>' if h.get('rufname') else ''}
          <table class="info-table">
            <tr><th>Geschlecht</th><td>{geschlecht}</td><th>Geburtsdatum</th><td>{_fmt_date(h.get('geburtsdatum'))}</td></tr>
            <tr><th>Chip-Nr.</th><td>{h.get('chip_nr') or '—'}</td><th>Zuchtbuchnr.</th><td>{h.get('zuchtbuchnummer') or '—'}</td></tr>
            <tr><th>Farbe</th><td>{h.get('farbe') or '—'}</td><th>Tätowierung</th><td>{h.get('taetowiernummer') or '—'}</td></tr>
            <tr><th>Züchter</th><td>{h.get('zuechter_name') or '—'}</td><th>Eigentümer</th><td>{h.get('eigentuemer_name') or '—'}</td></tr>
          </table>

          <h3>Stammbaum</h3>
          {_pedigree_html(tree) if tree else '<p style="color:#9ca3af">Keine Elterntiere eingetragen.</p>'}

          <h3>Gesundheitstests</h3>
          <table class="data-table">
            <tr><th>Test</th><th>Ergebnis</th><th>Datum</th><th>Labor</th><th>Untersucher</th></tr>
            {health_rows}
          </table>

          <h3>Genetische Tests</h3>
          <table class="data-table">
            <tr><th>Marker</th><th>Ergebnis</th><th>Datum</th><th>Labor</th></tr>
            {genetic_rows}
          </table>

          <h3>Titel &amp; Auszeichnungen</h3>
          <table class="data-table">
            <tr><th>Titel</th><th>Typ</th><th>Datum</th><th>Ort</th><th>Richter</th></tr>
            {title_rows}
          </table>
        </div>"""

    litters_html = ""
    for l in data["litters"]:
        lid = l["id"]
        l_puppies = [p for p in data["puppies"] if p["wurf_id"] == lid]
        puppy_rows = "".join(
            f'<tr><td>{p.get("name") or "—"}</td>'
            f'<td>{"Rüde" if p.get("geschlecht")=="maennlich" else "Hündin" if p.get("geschlecht")=="weiblich" else "—"}</td>'
            f'<td>{p.get("farbe") or "—"}</td><td>{p.get("chip_nr") or "—"}</td>'
            f'<td>{p.get("status") or "—"}</td></tr>'
            for p in l_puppies
        ) or "<tr><td colspan=5 style='color:#9ca3af'>Keine Welpen eingetragen</td></tr>"

        eltern = " × ".join(filter(None, [l.get("vater_name"), l.get("mutter_name")])) or "—"
        datum = _fmt_date(l.get("geburt_datum") or l.get("erwartetes_datum"))
        status_label = {"geplant": "Geplant", "geboren": "Geboren", "verfuegbar": "Verfügbar", "abgeschlossen": "Abgeschlossen"}.get(l.get("status",""), l.get("status",""))

        litters_html += f"""
        <div class="litter-card">
          <div style="display:flex;align-items:baseline;gap:12px;margin-bottom:8px">
            <h3 style="margin:0">{eltern}</h3>
            <span style="color:#6b7280;font-size:13px">{datum} · {status_label}</span>
          </div>
          {f'<p style="margin:0 0 12px;color:#374151">{l["beschreibung"]}</p>' if l.get("beschreibung") else ''}
          <table class="data-table">
            <tr><th>Name</th><th>Geschlecht</th><th>Farbe</th><th>Chip-Nr.</th><th>Status</th></tr>
            {puppy_rows}
          </table>
        </div>"""

    return f"""<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="UTF-8">
  <title>Zuchtkartei — {p.get('zwingername','')}</title>
  <style>
    @media print {{
      .no-print {{ display:none }}
      body {{ font-size:11pt }}
      .dog-card, .litter-card {{ page-break-inside:avoid }}
    }}
    * {{ box-sizing:border-box }}
    body {{ font-family:'Segoe UI',Arial,sans-serif;color:#1f2937;margin:0;padding:24px;max-width:1100px;margin:0 auto }}
    h1 {{ color:#7c3aed;margin:0 0 4px }}
    h2 {{ color:#7c3aed;border-bottom:2px solid #ede9fe;padding-bottom:6px }}
    h3 {{ color:#374151;font-size:14px;margin:16px 0 8px }}
    .header {{ background:#f5f3ff;border:1px solid #ddd6fe;border-radius:8px;padding:20px 24px;margin-bottom:24px }}
    .dog-card, .litter-card {{
      border:1px solid #e5e7eb;border-radius:8px;padding:20px 24px;margin-bottom:20px
    }}
    .info-table {{ border-collapse:collapse;width:100%;margin-bottom:8px }}
    .info-table th {{ text-align:left;color:#6b7280;font-size:12px;padding:3px 8px 3px 0;width:120px }}
    .info-table td {{ padding:3px 8px 3px 0;font-size:13px }}
    .data-table {{ border-collapse:collapse;width:100%;font-size:12px }}
    .data-table th {{ background:#f9fafb;padding:6px 10px;text-align:left;border-bottom:2px solid #e5e7eb;color:#374151 }}
    .data-table td {{ padding:5px 10px;border-bottom:1px solid #f3f4f6 }}
    .data-table tr:last-child td {{ border-bottom:none }}
    .badge-group {{ display:flex;gap:4px;flex-wrap:wrap }}
    footer {{ color:#9ca3af;font-size:11px;margin-top:32px;border-top:1px solid #e5e7eb;padding-top:12px }}
  </style>
</head>
<body>
  <div class="header">
    <h1>{p.get('zwingername','Mein Zwinger')}</h1>
    <div style="color:#6b7280;margin-bottom:12px">Exportiert am {today} · banyaro.app</div>
    <table class="info-table">
      <tr><th>Rasse</th><td>{p.get('rasse_text','—')}</td><th>Verein</th><td>{p.get('verein','—')}</td></tr>
      <tr><th>Stadt</th><td>{p.get('stadt','—')}</td><th>VDH</th><td>{'Ja' if p.get('vdh_mitglied') else 'Nein'}</td></tr>
      {f'<tr><th>Website</th><td colspan=3><a href="{p["website"]}">{p["website"]}</a></td></tr>' if p.get('website') else ''}
    </table>
    {f'<p style="margin:12px 0 0;color:#374151">{p["beschreibung"]}</p>' if p.get('beschreibung') else ''}
  </div>

  <h2>Hunde ({len(data['hunde'])})</h2>
  {hunde_html or '<p style="color:#9ca3af">Keine Hunde eingetragen.</p>'}

  <h2>Würfe ({len(data['litters'])})</h2>
  {litters_html or '<p style="color:#9ca3af">Keine Würfe eingetragen.</p>'}

  <footer>Erstellt mit Banyaro — Die App für Hunde und ihre Menschen · banyaro.app</footer>
</body>
</html>"""


# ------------------------------------------------------------------
# ODS-Export
# ------------------------------------------------------------------
def _generate_ods(data: dict) -> bytes:
    from odf.opendocument import OpenDocumentSpreadsheet
    from odf.style import Style, TextProperties, TableColumnProperties
    from odf.text import P
    from odf.table import Table, TableColumn, TableRow, TableCell

    doc = OpenDocumentSpreadsheet()

    def add_style(name, bold=False, bg=None, color=None):
        style = Style(name=name, family="table-cell")
        tp = TextProperties()
        if bold:
            tp.setAttribute("fo:font-weight", "bold")
        if color:
            tp.setAttribute("fo:color", color)
        style.addElement(tp)
        doc.styles.addElement(style)
        return style

    header_style = add_style("Header", bold=True, color="#ffffff")
    normal_style = add_style("Normal")

    def cell(value, style=None):
        tc = TableCell()
        if style:
            tc.setAttribute("table:style-name", style.getAttribute("style:name"))
        tc.addElement(P(text=str(value) if value is not None else ""))
        return tc

    def header_row(sheet, cols):
        tr = TableRow()
        for c in cols:
            tr.addElement(cell(c, header_style))
        sheet.addElement(tr)

    def data_row(sheet, vals):
        tr = TableRow()
        for v in vals:
            tr.addElement(cell(v))
        sheet.addElement(tr)

    # Sheet: Hunde
    sheet_hunde = Table(name="Hunde")
    header_row(sheet_hunde, ["Name", "Rufname", "Geschlecht", "Geburtsdatum", "Chip-Nr.", "Zuchtbuchnummer", "Farbe", "Tätowierung", "Züchter", "Eigentümer", "Notiz"])
    for h in data["hunde"]:
        g = {"maennlich": "Rüde", "weiblich": "Hündin"}.get(h.get("geschlecht",""), "")
        data_row(sheet_hunde, [h["name"], h.get("rufname",""), g, h.get("geburtsdatum",""),
                                h.get("chip_nr",""), h.get("zuchtbuchnummer",""), h.get("farbe",""),
                                h.get("taetowiernummer",""), h.get("zuechter_name",""),
                                h.get("eigentuemer_name",""), h.get("notiz","")])
    doc.spreadsheet.addElement(sheet_hunde)

    # Sheet: Gesundheitstests
    sheet_health = Table(name="Gesundheitstests")
    header_row(sheet_health, ["Hund", "Test-Typ", "Test-Name", "Ergebnis", "Datum", "Gültig bis", "Untersucher", "Labor", "Zertifikat-Nr."])
    hund_map = {h["id"]: h["name"] for h in data["hunde"]}
    for r in data["health"]:
        data_row(sheet_health, [hund_map.get(r["hund_id"],""), r["test_typ"], r.get("test_name",""),
                                  r["ergebnis"], r.get("untersuch_am",""), r.get("gueltig_bis",""),
                                  r.get("untersucher",""), r.get("labor",""), r.get("zertifikat_nr","")])
    doc.spreadsheet.addElement(sheet_health)

    # Sheet: Gentests
    sheet_gen = Table(name="Gentests")
    header_row(sheet_gen, ["Hund", "Marker", "Kategorie", "Genotyp", "Ergebnis", "Getestet am", "Labor", "Zertifikat-Nr."])
    for r in data["genetic"]:
        data_row(sheet_gen, [hund_map.get(r["hund_id"],""), r["marker_name"], r.get("marker_kategorie",""),
                               r.get("genotyp",""), r.get("ergebnis_klasse",""), r.get("getestet_am",""),
                               r.get("labor",""), r.get("zertifikat_nr","")])
    doc.spreadsheet.addElement(sheet_gen)

    # Sheet: Titel
    sheet_titles = Table(name="Titel")
    header_row(sheet_titles, ["Hund", "Titel", "Typ", "Verliehen am", "Ort", "Ausstellung", "Richter", "Formwert"])
    for r in data["titles"]:
        data_row(sheet_titles, [hund_map.get(r["hund_id"],""), r["titel_name"], r["titel_typ"],
                                  r.get("verliehen_am",""), r.get("ort",""), r.get("ausstellung",""),
                                  r.get("richter",""), r.get("formwert","")])
    doc.spreadsheet.addElement(sheet_titles)

    # Sheet: Würfe
    sheet_litters = Table(name="Würfe")
    header_row(sheet_litters, ["Vater", "Mutter", "Geburtsdatum", "Erwartetes Datum", "Status", "Welpen gesamt", "Welpen verfügbar", "Preisspanne", "Gesundheitstests", "Beschreibung"])
    for l in data["litters"]:
        status = {"geplant":"Geplant","geboren":"Geboren","verfuegbar":"Verfügbar","abgeschlossen":"Abgeschlossen"}.get(l.get("status",""), l.get("status",""))
        data_row(sheet_litters, [l.get("vater_name",""), l.get("mutter_name",""),
                                   l.get("geburt_datum",""), l.get("erwartetes_datum",""),
                                   status, l.get("welpen_gesamt",""), l.get("welpen_verfuegbar",""),
                                   l.get("preis_spanne",""), l.get("gesundheitstests",""),
                                   l.get("beschreibung","")])
    doc.spreadsheet.addElement(sheet_litters)

    # Sheet: Welpen
    sheet_puppies = Table(name="Welpen")
    header_row(sheet_puppies, ["Wurf (Vater × Mutter)", "Name", "Geschlecht", "Farbe", "Chip-Nr.", "Geburtsgewicht (g)", "Status", "Notiz"])
    litter_map = {l["id"]: f"{l.get('vater_name','?')} × {l.get('mutter_name','?')}" for l in data["litters"]}
    for p in data["puppies"]:
        g = {"maennlich":"Rüde","weiblich":"Hündin"}.get(p.get("geschlecht",""),"")
        data_row(sheet_puppies, [litter_map.get(p["wurf_id"],""), p.get("name",""), g,
                                   p.get("farbe",""), p.get("chip_nr",""),
                                   p.get("geburtsgewicht",""), p.get("status",""), p.get("notiz","")])
    doc.spreadsheet.addElement(sheet_puppies)

    # Sheet: Gewichte
    sheet_weights = Table(name="Gewichtsverlauf")
    header_row(sheet_weights, ["Welpe", "Gewicht (g)", "Gemessen am"])
    puppy_map = {p["id"]: p.get("name","") or f"Welpe #{p['id']}" for p in data["puppies"]}
    for w in data["weights"]:
        data_row(sheet_weights, [puppy_map.get(w["welpe_id"],""), w["gewicht_g"], w.get("gemessen_am","")])
    doc.spreadsheet.addElement(sheet_weights)

    buf = io.BytesIO()
    doc.save(buf)
    return buf.getvalue()


# ------------------------------------------------------------------
# GET /api/breeder/export — ZIP mit HTML + ODS
# ------------------------------------------------------------------
@router.get("/breeder/export")
async def export_breeder_data(user=Depends(_require_breeder)):
    data = _collect_data(user["id"])
    if not data:
        raise HTTPException(404, "Kein Züchter-Profil vorhanden.")

    zwinger = data["profile"].get("zwingername", "export").replace(" ", "_")
    today   = date.today().strftime("%Y-%m-%d")
    name    = f"banyaro_{zwinger}_{today}"

    try:
        html_bytes = _generate_html(data).encode("utf-8")
        ods_bytes  = _generate_ods(data)
    except Exception as e:
        logger.error(f"Export-Fehler: {e}", exc_info=True)
        raise HTTPException(500, "Fehler beim Erstellen des Exports.")

    zip_buf = io.BytesIO()
    with zipfile.ZipFile(zip_buf, "w", zipfile.ZIP_DEFLATED) as zf:
        zf.writestr(f"{name}.html", html_bytes)
        zf.writestr(f"{name}.ods",  ods_bytes)

    zip_buf.seek(0)
    return StreamingResponse(
        zip_buf,
        media_type="application/zip",
        headers={"Content-Disposition": f'attachment; filename="{name}.zip"'},
    )
