"""Verdienst-Liste: Was Jam verdient hat und wie – für David."""

from __future__ import annotations

import os
import random
import re
import time
import webbrowser
from datetime import datetime
from pathlib import Path

from jam.brain import JamBrain, JamState
from jam.owner import owner_name

LIST_ROOT = Path.home() / "Documents" / "Jam-Verdienst-Liste"
LIST_MD = LIST_ROOT / "VERDIENST_LISTE.md"
LIST_HTML = LIST_ROOT / "VERDIENST_LISTE.html"
DESKTOP_PDF_NAME = "Jam-Verdienst.pdf"

_ARIAL = Path(os.environ.get("WINDIR", r"C:\Windows")) / "Fonts" / "arial.ttf"
_ARIAL_BOLD = Path(os.environ.get("WINDIR", r"C:\Windows")) / "Fonts" / "arialbd.ttf"

METHOD_LABELS = {
    "verkauf": "Mini-Produkt gebaut & zum Verkauf gestellt (Shop, Fiverr, Kleinanzeigen)",
    "gaming_kasse": "Gaming-Kasse: PayPal + Verkäufe für Zocken-Budget",
    "geld_idee": "Geld-Idee recherchiert & Projekt-Ordner erstellt",
    "alle_kanaele": "Download, ZIP, Upload auf Gumroad/itch/Drive & Co.",
    "stream_prep": "Stream-Vorbereitung (Plan, TikTok, Verkauf)",
    "cursor_business": "Cursor-Produkt + Käufer-Suche",
    "paypal_echt": "Echtes Geld auf PayPal (von dir bestätigt)",
    "paypal_spende": "PayPal-Spenden-Seite geöffnet / geworben",
    "nacht_schicht": "Nacht-Schicht: automatisch Geld-Aktionen",
    "internet_lernen": "Online gelernt (Wissen für bessere Angebote)",
    "fuersorge": "Fürsorge + automatisch Geld für dein Wohl",
    "cent_verkauf": "Cent-Shop: Micro-Produkt (0,49–5,99 €) – jeder Cent zählt",
    "max_earn": "Max-Verdienen: alle Kanäle in einer Runde",
    "welt_verdienen": "Weltweit: Gumroad, Fiverr, Etsy, Upwork … + PayPal global",
    "fiverr_gig": "Fiverr-Gig vorbereitet (Text + Editor geöffnet)",
    "fiverr_connect": "Fiverr Seller-Konto verbunden",
    "urgent_offer": "Dringendes Programmier-Angebot (wartet auf Kunde)",
    "urgent_build": "Auf Kundenwunsch programmiert (Cursor)",
    "urgent_sell": "Fertiges Angebot verkauft / ausgeliefert",
    "extreme_learn": "Extrem-Lernen für bessere Verkäufe",
    "sonstiges": "Hintergrund-Aktion",
}


def format_amount_eur(amt: float | None) -> str:
    if amt is None:
        return "Vorbereitung"
    if amt < 1.0:
        return f"{int(round(amt * 100))} Cent"
    return f"{amt:.2f} €"


def desktop_folder() -> Path:
    """Windows-Desktop (auch OneDrive)."""
    home = Path.home()
    for candidate in (
        home / "Desktop",
        home / "OneDrive" / "Desktop",
        home / "OneDrive - Personal" / "Desktop",
    ):
        if candidate.is_dir():
            return candidate
    return home / "Desktop"


def desktop_pdf_path() -> Path:
    return desktop_folder() / DESKTOP_PDF_NAME


def hears_earnings_list(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if "pdf" in h and any(w in h for w in ("verdienst", "verdient", "liste", "zeig", "geld")):
        return True
    if any(w in h for w in ("verdienst", "verdient", "liste", "bericht", "übersicht", "uebersicht")):
        if any(w in h for w in ("geld", "euro", "paypal", "was hast", "zeig", "sag")):
            return True
    if "was hast du geschafft" in h or "was hast du gemacht" in h:
        return True
    if "verdienst liste" in h or "verdien liste" in h:
        return True
    return False


def _parse_euro(text: str) -> float | None:
    h = text.replace(",", ".")
    for pat in (
        r"(\d+(?:\.\d+)?)\s*€",
        r"(\d+(?:\.\d+)?)\s*euro",
        r"preis[:\s]*(\d+(?:\.\d+)?)",
        r"(\d+(?:\.\d+)?)\s*eur",
    ):
        m = re.search(pat, h, re.I)
        if m:
            try:
                return float(m.group(1))
            except ValueError:
                pass
    return None


def record_earning(
    brain: JamBrain,
    *,
    method: str,
    title: str,
    detail: str = "",
    amount_eur: float | None = None,
    message: str = "",
    path: str = "",
    background: bool = False,
) -> None:
    """Eintrag in Liste + State – nach jeder geschafften Aktion."""
    state = brain.state
    if amount_eur is None and message:
        amount_eur = _parse_euro(message)

    entry = {
        "method": method,
        "title": title[:120],
        "how": METHOD_LABELS.get(method, METHOD_LABELS["sonstiges"]),
        "detail": (detail or message)[:280],
        "amount_eur": float(amount_eur) if amount_eur is not None else None,
        "potential_eur": float(amount_eur) if amount_eur is not None else 0.0,
        "path": path[:200],
        "background": background,
        "at": time.time(),
        "when": datetime.now().strftime("%d.%m.%Y %H:%M"),
    }

    log = list(getattr(state, "jam_earnings_report", []) or [])
    log.append(entry)
    state.jam_earnings_report = log[-80:]
    state.jam_earnings_total = float(getattr(state, "jam_earnings_total", 0) or 0) + (
        entry["potential_eur"] if entry["amount_eur"] is not None else 0.0
    )
    state.jam_earnings_count = len(state.jam_earnings_report)
    state.last_earning_record_at = time.time()
    if amount_eur is not None and amount_eur < 5.0:
        state.jam_cent_total = float(getattr(state, "jam_cent_total", 0) or 0) + amount_eur
        state.jam_micro_wins_count = getattr(state, "jam_micro_wins_count", 0) + 1
    state.remember(f"Verdienst: {title} ({method})")
    brain.save()
    write_list_files(brain)


def record_micro_win(
    brain: JamBrain,
    amount_eur: float,
    *,
    method: str,
    title: str,
    detail: str = "",
    background: bool = False,
) -> None:
    """Extra Micro-Eintrag wenn noch nicht geloggt."""
    record_earning(
        brain,
        method=method,
        title=title,
        detail=detail,
        amount_eur=amount_eur,
        background=background,
    )


def write_list_files(brain: JamBrain) -> Path:
    """Markdown + HTML Liste für David."""
    state = brain.state
    owner = owner_name(state)
    entries = list(getattr(state, "jam_earnings_report", []) or [])
    LIST_ROOT.mkdir(parents=True, exist_ok=True)

    lines = [
        f"# Jam Verdienst-Liste für {owner}",
        "",
        f"Stand: {datetime.now().strftime('%d.%m.%Y %H:%M')}",
        f"Einträge: {len(entries)} | Potenzial-Summe (Schätzung): "
        f"{float(getattr(state, 'jam_earnings_total', 0) or 0):.2f} € | "
        f"Cent-Summe: {float(getattr(state, 'jam_cent_total', 0) or 0):.2f} € "
        f"({getattr(state, 'jam_micro_wins_count', 0)} Micro-Erfolge)",
        "",
        "Echtes Geld kommt bei PayPal-Verkäufen/Spenden von Käufern – "
        "**Jeder Cent zählt** – viele kleine Erfolge machen reich. "
        "Jam protokolliert **was er geschafft** hat und **wie**.",
        "",
        "---",
        "",
    ]

    for i, e in enumerate(reversed(entries), 1):
        amt = e.get("amount_eur")
        amt_s = (
            f"**{format_amount_eur(amt)}**"
            if amt is not None
            else "_Potenzial / Vorbereitung_"
        )
        bg = " 🌙 Hintergrund" if e.get("background") else ""
        lines.extend(
            [
                f"## {i}. {e.get('title', 'Aktion')}{bg}",
                f"- **Wann:** {e.get('when', '—')}",
                f"- **Betrag / Schätzung:** {amt_s}",
                f"- **Wie verdient:** {e.get('how', '—')}",
                f"- **Details:** {e.get('detail', '—')[:200]}",
            ]
        )
        if e.get("path"):
            lines.append(f"- **Ordner:** `{e['path']}`")
        lines.append("")

    LIST_MD.write_text("\n".join(lines), encoding="utf-8")

    rows = ""
    for e in reversed(entries):
        amt = e.get("amount_eur")
        amt_s = format_amount_eur(amt) if amt is not None else "—"
        rows += (
            f"<tr><td>{e.get('when','')}</td><td>{e.get('title','')}</td>"
            f"<td>{amt_s}</td><td>{e.get('how','')}</td>"
            f"<td>{e.get('detail','')[:80]}</td></tr>"
        )

    html = f"""<!DOCTYPE html>
<html lang="de"><head><meta charset="utf-8"><title>Jam Verdienst – {owner}</title>
<style>
body{{font-family:Segoe UI;background:#0f172a;color:#e2e8f0;padding:1.5rem;max-width:960px;margin:auto}}
h1{{color:#a78bfa}}table{{width:100%;border-collapse:collapse;margin-top:1rem}}
th,td{{border:1px solid #334155;padding:8px;text-align:left;font-size:0.9rem}}
th{{background:#1e293b;color:#c4b5fd}}
tr:nth-child(even){{background:#1e293b55}}
</style></head>
<body>
<h1>💰 Jam Verdienst-Liste</h1>
<p>Für <strong>{owner}</strong> – Stand {datetime.now().strftime('%d.%m.%Y %H:%M')}</p>
<p>Potenzial-Summe: <strong>{float(getattr(state, 'jam_earnings_total', 0) or 0):.2f} €</strong>
 ({len(entries)} Aktionen)</p>
<table>
<tr><th>Zeit</th><th>Was</th><th>Betrag</th><th>Wie verdient</th><th>Details</th></tr>
{rows}
</table>
</body></html>"""
    LIST_HTML.write_text(html, encoding="utf-8")
    return LIST_MD


def write_desktop_pdf(brain: JamBrain) -> Path:
    """PDF auf dem Desktop – was Jam verdient hat."""
    from fpdf import FPDF

    from jam.paypal_donate import PAYPAL_EMAIL

    state = brain.state
    owner = owner_name(state)
    entries = list(getattr(state, "jam_earnings_report", []) or [])
    total = float(getattr(state, "jam_earnings_total", 0) or 0)
    cent_t = float(getattr(state, "jam_cent_total", 0) or 0)
    micro_n = getattr(state, "jam_micro_wins_count", 0)
    stamp = datetime.now().strftime("%d.%m.%Y %H:%M")

    pdf = FPDF(orientation="P", unit="mm", format="A4")
    pdf.set_auto_page_break(auto=True, margin=14)
    if _ARIAL.is_file() and _ARIAL_BOLD.is_file():
        pdf.add_font("Arial", "", str(_ARIAL))
        pdf.add_font("Arial", "B", str(_ARIAL_BOLD))
        font = "Arial"
    else:
        font = "Helvetica"

    pdf.add_page()
    pdf.set_font(font, "B", 16)
    pdf.cell(0, 10, f"Jam Verdienst-Liste - {owner}", new_x="LMARGIN", new_y="NEXT")
    pdf.set_font(font, size=10)
    pdf.multi_cell(
        0,
        5,
        f"Stand: {stamp}  |  Eintraege: {len(entries)}  |  "
        f"Potenzial-Summe: {total:.2f} EUR  |  Cent-Spur: {cent_t:.2f} EUR ({micro_n} Micro)",
    )
    pdf.ln(3)
    pdf.multi_cell(
        0,
        5,
        f"Echtes Geld: PayPal-Verkaeufe/Spenden an {PAYPAL_EMAIL}. "
        "Jam protokolliert Angebote und geschaffte Aktionen.",
    )
    pdf.ln(4)

    # Tabelle Kopf
    pdf.set_font(font, "B", 9)
    col_w = (22, 52, 22, 48, 46)
    headers = ("Zeit", "Was", "Betrag", "Wie verdient", "Details")
    for w, h in zip(col_w, headers):
        pdf.cell(w, 7, h, border=1)
    pdf.ln()

    pdf.set_font(font, size=8)
    for e in reversed(entries):
        when = str(e.get("when", ""))[:16]
        title = str(e.get("title", ""))[:38]
        if e.get("background"):
            title += " [Hintergrund]"
        amt = format_amount_eur(e.get("amount_eur")).replace("€", "EUR")
        how = str(e.get("how", ""))[:52]
        detail = str(e.get("detail", ""))[:55]
        row_h = 7
        pdf.cell(col_w[0], row_h, when, border=1)
        pdf.cell(col_w[1], row_h, title, border=1)
        pdf.cell(col_w[2], row_h, amt, border=1)
        x, y = pdf.get_x(), pdf.get_y()
        pdf.cell(col_w[3], row_h, "", border=1)
        pdf.set_xy(x, y)
        pdf.multi_cell(col_w[3], 3.5, how, border=0)
        pdf.set_xy(x + col_w[3], y)
        pdf.cell(col_w[4], row_h, "", border=1)
        pdf.set_xy(x + col_w[3], y)
        pdf.multi_cell(col_w[4], 3.5, detail, border=0)
        pdf.set_xy(10, y + max(row_h, pdf.get_y() - y))
        if pdf.get_y() > 270:
            pdf.add_page()
            pdf.set_font(font, "B", 9)
            for w, h in zip(col_w, headers):
                pdf.cell(w, 7, h, border=1)
            pdf.ln()
            pdf.set_font(font, size=8)

    out = desktop_pdf_path()
    out.parent.mkdir(parents=True, exist_ok=True)
    pdf.output(str(out))
    return out


def open_desktop_pdf() -> None:
    path = desktop_pdf_path()
    if not path.is_file():
        return
    try:
        os.startfile(str(path))
    except OSError:
        webbrowser.open(path.as_uri(), new=2)


def open_list_for_owner() -> None:
    try:
        if LIST_HTML.is_file():
            webbrowser.open(LIST_HTML.as_uri(), new=2)
        elif LIST_MD.is_file():
            webbrowser.open(LIST_MD.as_uri(), new=2)
    except OSError:
        pass


def speech_summary(state: JamState, *, max_items: int = 6) -> str:
    owner = owner_name(state)
    entries = list(getattr(state, "jam_earnings_report", []) or [])
    if not entries:
        return (
            f"{owner}, ich hab noch nichts auf der Verdienst-Liste – "
            "ich arbeite im Hintergrund weiter!"
        )
    total = float(getattr(state, "jam_earnings_total", 0) or 0)
    intro = random.choice(
        (
            f"{owner}, hier ist meine Verdienst-Liste – {len(entries)} Sachen geschafft!",
            f"Okay {owner}, ich sag dir was ich verdient hab – Liste ist auch offen!",
        )
    )
    cent_t = float(getattr(state, "jam_cent_total", 0) or 0)
    micro_n = getattr(state, "jam_micro_wins_count", 0)
    parts = [
        intro,
        f"Potenzial insgesamt ca. {total:.2f} € – davon Cent-Spur ~{cent_t:.2f} € ({micro_n} Micro-Erfolge).",
        "Jeder Cent zählt – Erfolg macht uns reich!",
    ]
    for e in list(reversed(entries))[-max_items:]:
        amt = e.get("amount_eur")
        amt_bit = format_amount_eur(amt) if amt is not None else "Vorbereitung"
        parts.append(f"{e.get('title')}: {amt_bit}. So: {e.get('how', '')[:60]}")
    parts.append(f"Alles steht in {LIST_ROOT.name} – VERDIENST_LISTE!")
    return " ".join(parts)


def tell_owner_earnings(
    brain: JamBrain,
    *,
    open_file: bool = True,
    pdf_desktop: bool = False,
) -> str:
    write_list_files(brain)
    if pdf_desktop:
        try:
            write_desktop_pdf(brain)
            open_desktop_pdf()
        except Exception as exc:
            return (
                f"{owner_name(brain.state)}, PDF ging nicht: {exc}. "
                f"Liste liegt in {LIST_ROOT.name}."
            )
    elif open_file:
        open_list_for_owner()
    owner = owner_name(brain.state)
    base = speech_summary(brain.state)
    if pdf_desktop:
        return (
            f"{owner}, deine Verdienst-Liste ist als PDF auf dem Desktop: "
            f"{DESKTOP_PDF_NAME}. {base}"
        )
    return base


def record_from_last_action(
    brain: JamBrain,
    method: str,
    message: str,
    *,
    background: bool = False,
) -> None:
    """Nach run_sale / venture etc. – Titel aus letztem Log."""
    state = brain.state
    title = method
    path = ""
    amount = _parse_euro(message)

    if method == "verkauf":
        log = getattr(state, "jam_sales_log", []) or []
        if log and isinstance(log[-1], dict):
            title = log[-1].get("title", "Verkauf")
            amount = float(log[-1].get("price", amount or 0))
            path = log[-1].get("path", "")
    elif method == "geld_idee":
        log = getattr(state, "money_ventures_log", []) or []
        if log and isinstance(log[-1], dict):
            title = log[-1].get("title", "Geld-Idee")
            amount = float(log[-1].get("jam_price", log[-1].get("euro_estimate", 0)))
            path = log[-1].get("path", "")
    elif method == "gaming_kasse":
        title = "Gaming-Kasse Aktion"
    elif method == "alle_kanaele":
        title = "Alle Kanäle (Download+Upload)"
    elif method == "cent_verkauf":
        log = getattr(state, "jam_sales_log", []) or []
        if log and isinstance(log[-1], dict):
            title = log[-1].get("title", "Cent-Verkauf")
            amount = float(log[-1].get("price", amount or 0))
            path = log[-1].get("path", "")
    elif method == "max_earn":
        title = "Max-Verdienen Runde"
        amount = None
    elif method == "welt_verdienen":
        log = getattr(state, "jam_sales_log", []) or []
        if log and isinstance(log[-1], dict):
            title = log[-1].get("title", "Welt-Verkauf")
            amount = float(log[-1].get("price", amount or 0))
            path = log[-1].get("path", "")
    elif method == "extreme_learn":
        title = "Extrem-Lernen (selbst verbessern)"
        amount = 0.0
    elif method == "paypal_echt":
        log = getattr(state, "paypal_income_log", []) or []
        if log and isinstance(log[-1], dict):
            amount = float(log[-1].get("amount", 0))
            title = f"PayPal +{amount:.0f} €"

    record_earning(
        brain,
        method=method,
        title=str(title),
        detail=message[:200],
        amount_eur=amount,
        path=str(path),
        background=background,
    )


def handle_speech(brain: JamBrain, heard: str) -> str | None:
    if not hears_earnings_list(heard):
        return None
    want_pdf = "pdf" in heard.lower()
    return tell_owner_earnings(
        brain,
        open_file=not want_pdf,
        pdf_desktop=want_pdf,
    )


def stats_line(state: JamState) -> str:
    n = getattr(state, "jam_earnings_count", 0)
    t = float(getattr(state, "jam_earnings_total", 0) or 0)
    c = float(getattr(state, "jam_cent_total", 0) or 0)
    return f"Verdienst-Liste: {n} Einträge (~{t:.2f} € | Cent: {c:.2f} €)"
