"""BAN YARO — Digitaler Hundepass"""

import io
import secrets
from datetime import date, datetime, timedelta
from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from typing import Optional
from database import db
from auth import get_current_user

router = APIRouter()


# ------------------------------------------------------------------
# Schemas
# ------------------------------------------------------------------
class PassportMeta(BaseModel):
    blutgruppe:     Optional[str] = None
    allergien:      Optional[str] = None
    besonderheiten: Optional[str] = None


class VaccinationCreate(BaseModel):
    krankheit: str
    datum:     str
    naechste:  Optional[str] = None
    tierarzt:  Optional[str] = None
    charge_nr: Optional[str] = None


class MedicationCreate(BaseModel):
    name:      str
    dosierung: Optional[str] = None
    von:       Optional[str] = None
    bis:       Optional[str] = None
    notiz:     Optional[str] = None


# ------------------------------------------------------------------
# Hilfsfunktion: Eigentümer-Prüfung
# ------------------------------------------------------------------
def _get_own_dog(conn, dog_id: int, user_id: int):
    dog = conn.execute(
        "SELECT * FROM dogs WHERE id=? AND user_id=?", (dog_id, user_id)
    ).fetchone()
    if not dog:
        raise HTTPException(404, "Hund nicht gefunden.")
    return dog


def _load_passport_data(conn, dog_id: int) -> dict:
    dog = conn.execute("SELECT * FROM dogs WHERE id=?", (dog_id,)).fetchone()
    if not dog:
        raise HTTPException(404, "Hund nicht gefunden.")

    meta = conn.execute(
        "SELECT * FROM dog_passport_meta WHERE dog_id=?", (dog_id,)
    ).fetchone()
    vaccinations = conn.execute(
        "SELECT * FROM vaccinations WHERE dog_id=? ORDER BY datum DESC", (dog_id,)
    ).fetchall()
    medications = conn.execute(
        "SELECT * FROM medications WHERE dog_id=? ORDER BY von DESC, id DESC", (dog_id,)
    ).fetchall()

    return {
        "dog":          dict(dog),
        "meta":         dict(meta) if meta else {},
        "vaccinations": [dict(v) for v in vaccinations],
        "medications":  [dict(m) for m in medications],
    }


# ------------------------------------------------------------------
# GET /passport/{dog_id} — vollständige Passdaten
# ------------------------------------------------------------------
@router.get("/{dog_id}")
async def get_passport(dog_id: int, user=Depends(get_current_user)):
    with db() as conn:
        _get_own_dog(conn, dog_id, user["id"])
        return _load_passport_data(conn, dog_id)


# ------------------------------------------------------------------
# PUT /passport/{dog_id}/meta
# ------------------------------------------------------------------
@router.put("/{dog_id}/meta")
async def update_meta(dog_id: int, data: PassportMeta, user=Depends(get_current_user)):
    with db() as conn:
        _get_own_dog(conn, dog_id, user["id"])
        conn.execute("""
            INSERT INTO dog_passport_meta (dog_id, blutgruppe, allergien, besonderheiten, updated_at)
            VALUES (?, ?, ?, ?, datetime('now'))
            ON CONFLICT(dog_id) DO UPDATE SET
                blutgruppe     = excluded.blutgruppe,
                allergien      = excluded.allergien,
                besonderheiten = excluded.besonderheiten,
                updated_at     = excluded.updated_at
        """, (dog_id, data.blutgruppe, data.allergien, data.besonderheiten))
    return {"ok": True}


# ------------------------------------------------------------------
# POST /passport/{dog_id}/vaccinations
# ------------------------------------------------------------------
@router.post("/{dog_id}/vaccinations")
async def add_vaccination(dog_id: int, data: VaccinationCreate, user=Depends(get_current_user)):
    with db() as conn:
        _get_own_dog(conn, dog_id, user["id"])
        conn.execute("""
            INSERT INTO vaccinations (dog_id, krankheit, datum, naechste, tierarzt, charge_nr)
            VALUES (?, ?, ?, ?, ?, ?)
        """, (dog_id, data.krankheit, data.datum, data.naechste, data.tierarzt, data.charge_nr))
        row = conn.execute(
            "SELECT * FROM vaccinations WHERE dog_id=? ORDER BY id DESC LIMIT 1", (dog_id,)
        ).fetchone()
    return dict(row)


# ------------------------------------------------------------------
# DELETE /passport/{dog_id}/vaccinations/{vacc_id}
# ------------------------------------------------------------------
@router.delete("/{dog_id}/vaccinations/{vacc_id}", status_code=204)
async def delete_vaccination(dog_id: int, vacc_id: int, user=Depends(get_current_user)):
    with db() as conn:
        _get_own_dog(conn, dog_id, user["id"])
        conn.execute(
            "DELETE FROM vaccinations WHERE id=? AND dog_id=?", (vacc_id, dog_id)
        )


# ------------------------------------------------------------------
# POST /passport/{dog_id}/medications
# ------------------------------------------------------------------
@router.post("/{dog_id}/medications")
async def add_medication(dog_id: int, data: MedicationCreate, user=Depends(get_current_user)):
    with db() as conn:
        _get_own_dog(conn, dog_id, user["id"])
        conn.execute("""
            INSERT INTO medications (dog_id, name, dosierung, von, bis, notiz)
            VALUES (?, ?, ?, ?, ?, ?)
        """, (dog_id, data.name, data.dosierung, data.von, data.bis, data.notiz))
        row = conn.execute(
            "SELECT * FROM medications WHERE dog_id=? ORDER BY id DESC LIMIT 1", (dog_id,)
        ).fetchone()
    return dict(row)


# ------------------------------------------------------------------
# DELETE /passport/{dog_id}/medications/{med_id}
# ------------------------------------------------------------------
@router.delete("/{dog_id}/medications/{med_id}", status_code=204)
async def delete_medication(dog_id: int, med_id: int, user=Depends(get_current_user)):
    with db() as conn:
        _get_own_dog(conn, dog_id, user["id"])
        conn.execute(
            "DELETE FROM medications WHERE id=? AND dog_id=?", (med_id, dog_id)
        )


# ------------------------------------------------------------------
# POST /passport/{dog_id}/share — Share-Token erstellen
# ------------------------------------------------------------------
@router.post("/{dog_id}/share")
async def create_share(dog_id: int, user=Depends(get_current_user)):
    with db() as conn:
        _get_own_dog(conn, dog_id, user["id"])
        token = secrets.token_urlsafe(32)
        valid_until = (date.today() + timedelta(days=30)).isoformat()
        conn.execute("""
            INSERT INTO passport_shares (dog_id, token, valid_until)
            VALUES (?, ?, ?)
        """, (dog_id, token, valid_until))
    return {
        "token":       token,
        "valid_until": valid_until,
        "url":         f"/pass/{token}",
    }


# ------------------------------------------------------------------
# GET /passport/share/{token} — öffentlicher Endpunkt (kein Auth)
# ------------------------------------------------------------------
@router.get("/share/{token}")
async def get_shared_passport(token: str):
    with db() as conn:
        share = conn.execute(
            "SELECT * FROM passport_shares WHERE token=?", (token,)
        ).fetchone()
        if not share:
            raise HTTPException(404, "Link nicht gefunden.")
        if share["valid_until"] < date.today().isoformat():
            raise HTTPException(410, "Dieser Link ist abgelaufen.")
        return _load_passport_data(conn, share["dog_id"])


# ------------------------------------------------------------------
# GET /passport/{dog_id}/pdf — PDF generieren
# ------------------------------------------------------------------
@router.get("/{dog_id}/pdf")
async def download_pdf(dog_id: int, user=Depends(get_current_user)):
    with db() as conn:
        _get_own_dog(conn, dog_id, user["id"])
        data = _load_passport_data(conn, dog_id)

    pdf_bytes = _generate_pdf(data)
    dog_name  = data["dog"]["name"].replace(" ", "_")
    filename  = f"Hundepass_{dog_name}.pdf"

    return StreamingResponse(
        io.BytesIO(pdf_bytes),
        media_type="application/pdf",
        headers={"Content-Disposition": f'attachment; filename="{filename}"'},
    )


# ------------------------------------------------------------------
# PDF-Generierung mit fpdf2
# ------------------------------------------------------------------
def _generate_pdf(data: dict) -> bytes:
    try:
        from fpdf import FPDF
    except ImportError:
        raise HTTPException(500, "PDF-Bibliothek nicht verfügbar. Bitte fpdf2 installieren.")

    dog  = data["dog"]
    meta = data["meta"]
    vaccs = data["vaccinations"]
    meds  = data["medications"]

    # Datumsformatierung DE
    def _fmt_date(d):
        if not d:
            return "–"
        try:
            return datetime.strptime(d[:10], "%Y-%m-%d").strftime("%d.%m.%Y")
        except Exception:
            return d

    # Geschlecht
    geschlecht_map = {"m": "Rüde", "w": "Hündin"}

    pdf = FPDF()
    pdf.set_auto_page_break(auto=True, margin=20)
    pdf.add_page()

    # ---- Header ----
    pdf.set_fill_color(40, 167, 100)  # Ban Yaro Grün
    pdf.rect(0, 0, 210, 38, style="F")

    pdf.set_text_color(255, 255, 255)
    pdf.set_font("Helvetica", style="B", size=20)
    pdf.set_y(8)
    pdf.cell(0, 10, "Ban Yaro", align="C", ln=True)
    pdf.set_font("Helvetica", size=11)
    pdf.cell(0, 8, f"Digitaler Hundepass  —  {dog['name']}", align="C", ln=True)
    pdf.set_font("Helvetica", size=8)
    pdf.cell(0, 6, f"Erstellt am {date.today().strftime('%d.%m.%Y')}", align="C", ln=True)

    pdf.set_text_color(30, 30, 30)
    pdf.set_y(46)

    # ---- Hundedaten ----
    pdf.set_fill_color(245, 250, 247)
    pdf.set_draw_color(200, 200, 200)
    pdf.set_font("Helvetica", style="B", size=12)
    pdf.set_fill_color(235, 247, 240)
    pdf.cell(0, 8, "  Hundeangaben", ln=True, fill=True, border="B")
    pdf.ln(3)

    def _info_row(label, value):
        pdf.set_font("Helvetica", style="B", size=9)
        pdf.cell(45, 6, label + ":", ln=False)
        pdf.set_font("Helvetica", size=9)
        pdf.cell(0, 6, str(value) if value else "–", ln=True)

    _info_row("Name",        dog["name"])
    _info_row("Rasse",       dog.get("rasse") or "–")
    _info_row("Geburtstag",  _fmt_date(dog.get("geburtstag")))
    _info_row("Geschlecht",  geschlecht_map.get(dog.get("geschlecht", ""), "–"))
    _info_row("Chip-Nr.",    dog.get("chip_nr") or "–")
    if meta.get("blutgruppe"):
        _info_row("Blutgruppe", meta["blutgruppe"])

    pdf.ln(5)

    # ---- Allergien & Besonderheiten ----
    if meta.get("allergien") or meta.get("besonderheiten"):
        pdf.set_font("Helvetica", style="B", size=12)
        pdf.set_fill_color(235, 247, 240)
        pdf.cell(0, 8, "  Allergien & Besonderheiten", ln=True, fill=True, border="B")
        pdf.ln(3)
        if meta.get("allergien"):
            pdf.set_font("Helvetica", style="B", size=9)
            pdf.cell(45, 6, "Allergien:", ln=False)
            pdf.set_font("Helvetica", size=9)
            pdf.multi_cell(0, 6, meta["allergien"])
        if meta.get("besonderheiten"):
            pdf.set_font("Helvetica", style="B", size=9)
            pdf.cell(45, 6, "Besonderheiten:", ln=False)
            pdf.set_font("Helvetica", size=9)
            pdf.multi_cell(0, 6, meta["besonderheiten"])
        pdf.ln(5)

    # ---- Impfungen ----
    pdf.set_font("Helvetica", style="B", size=12)
    pdf.set_fill_color(235, 247, 240)
    pdf.cell(0, 8, "  Impfungen", ln=True, fill=True, border="B")
    pdf.ln(3)

    if vaccs:
        # Tabellen-Header
        pdf.set_fill_color(220, 240, 228)
        pdf.set_font("Helvetica", style="B", size=8)
        pdf.cell(50, 6, "Krankheit", border=1, fill=True)
        pdf.cell(25, 6, "Datum", border=1, fill=True)
        pdf.cell(25, 6, "Nächste fällig", border=1, fill=True)
        pdf.cell(55, 6, "Tierarzt", border=1, fill=True)
        pdf.cell(35, 6, "Charge-Nr.", border=1, fill=True, ln=True)

        pdf.set_font("Helvetica", size=8)
        for i, v in enumerate(vaccs):
            fill = (i % 2 == 0)
            pdf.set_fill_color(248, 252, 250) if fill else pdf.set_fill_color(255, 255, 255)
            pdf.cell(50, 6, (v["krankheit"] or "")[:28], border=1, fill=fill)
            pdf.cell(25, 6, _fmt_date(v["datum"]), border=1, fill=fill)
            pdf.cell(25, 6, _fmt_date(v["naechste"]), border=1, fill=fill)
            pdf.cell(55, 6, (v["tierarzt"] or "–")[:32], border=1, fill=fill)
            pdf.cell(35, 6, (v["charge_nr"] or "–")[:20], border=1, fill=fill, ln=True)
    else:
        pdf.set_font("Helvetica", style="I", size=9)
        pdf.set_text_color(140, 140, 140)
        pdf.cell(0, 6, "Keine Impfungen eingetragen.", ln=True)
        pdf.set_text_color(30, 30, 30)

    pdf.ln(5)

    # ---- Medikamente ----
    pdf.set_font("Helvetica", style="B", size=12)
    pdf.set_fill_color(235, 247, 240)
    pdf.cell(0, 8, "  Medikamente", ln=True, fill=True, border="B")
    pdf.ln(3)

    if meds:
        pdf.set_fill_color(220, 240, 228)
        pdf.set_font("Helvetica", style="B", size=8)
        pdf.cell(55, 6, "Medikament", border=1, fill=True)
        pdf.cell(35, 6, "Dosierung", border=1, fill=True)
        pdf.cell(25, 6, "Von", border=1, fill=True)
        pdf.cell(25, 6, "Bis", border=1, fill=True)
        pdf.cell(50, 6, "Notiz", border=1, fill=True, ln=True)

        pdf.set_font("Helvetica", size=8)
        for i, m in enumerate(meds):
            fill = (i % 2 == 0)
            pdf.set_fill_color(248, 252, 250) if fill else pdf.set_fill_color(255, 255, 255)
            pdf.cell(55, 6, (m["name"] or "")[:32], border=1, fill=fill)
            pdf.cell(35, 6, (m["dosierung"] or "–")[:22], border=1, fill=fill)
            pdf.cell(25, 6, _fmt_date(m["von"]), border=1, fill=fill)
            bis = _fmt_date(m["bis"]) if m["bis"] else "dauerhaft"
            pdf.cell(25, 6, bis, border=1, fill=fill)
            pdf.cell(50, 6, (m["notiz"] or "–")[:30], border=1, fill=fill, ln=True)
    else:
        pdf.set_font("Helvetica", style="I", size=9)
        pdf.set_text_color(140, 140, 140)
        pdf.cell(0, 6, "Keine Medikamente eingetragen.", ln=True)
        pdf.set_text_color(30, 30, 30)

    # ---- Footer ----
    pdf.set_y(-15)
    pdf.set_font("Helvetica", style="I", size=8)
    pdf.set_text_color(140, 140, 140)
    pdf.cell(0, 5, "Erstellt mit Ban Yaro  —  banyaro.app", align="C", ln=True)

    return bytes(pdf.output())
