"""
Mining-Verdienst-Bericht (GPU + USB) – Schätzung + Log, PDF auf Desktop.
Echtes BTC-Guthaben kommt nur von Pool/Wallet (nicht automatisch abgefragt).
"""

from __future__ import annotations

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

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

ROOT = Path(__file__).resolve().parent.parent
GPU_LOG = ROOT / "data" / "jam-gpu-mining.log"
GPU_CFG = ROOT / "data" / "jam-gpu-mining.json"
USB_CFG = ROOT / "data" / "usb-miner.json"
MINING_LOG = ROOT / "data" / "jam-mining.log"
DESKTOP_PDF_NAME = "Jam-Mining-Verdienst.pdf"
REPORT_DIR = Path.home() / "Documents" / "Jam-Mining-Bericht"

_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"


def desktop_folder() -> Path:
    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 _parse_gpu_sessions() -> list[dict]:
    """Aus jam-gpu-mining.log Start/Stop-Zeiten schätzen."""
    if not GPU_LOG.is_file():
        return []
    lines = GPU_LOG.read_text(encoding="utf-8", errors="replace").splitlines()
    sessions: list[dict] = []
    current: dict | None = None
    today = datetime.now().date()

    for line in lines:
        m = re.match(r"\[(\d{2}):(\d{2}):(\d{2})\]\s*(.*)", line.strip())
        if not m:
            continue
        h, mi, s, rest = int(m.group(1)), int(m.group(2)), int(m.group(3)), m.group(4)
        ts = datetime.combine(today, datetime.min.time()).replace(hour=h, minute=mi, second=s)
        if "direct start" in rest or "started pid" in rest:
            if current:
                sessions.append(current)
            power = 90
            pm = re.search(r"power=(\d+)%", rest)
            if pm:
                power = int(pm.group(1))
            mclk = None
            mm = re.search(r"mclk=(\d+)", rest)
            if mm:
                mclk = int(mm.group(1))
            algo = "ETCHASH"
            am = re.search(r"algo=(\w+)", rest)
            if am:
                algo = am.group(1)
            current = {
                "start": ts,
                "end": None,
                "power_percent": power,
                "mclk": mclk,
                "algo": algo,
                "worker": rest[-40:],
            }
        elif rest.strip() == "stopped" and current:
            current["end"] = ts
            sessions.append(current)
            current = None

    if current:
        current["end"] = datetime.now()
        sessions.append(current)

    for sess in sessions:
        if sess.get("end") and sess.get("start"):
            sec = max(0.0, (sess["end"] - sess["start"]).total_seconds())
            sess["hours"] = round(sec / 3600.0, 4)
            sess["minutes"] = round(sec / 60.0, 1)
        else:
            sess["hours"] = 0.0
            sess["minutes"] = 0.0
    return sessions


def collect_mining_summary(brain: JamBrain | None = None) -> dict:
    from jam.gpu_mining import estimate_gpu_earnings, is_gpu_mining_running

    state = brain.state if brain else None
    btc = ""
    if GPU_CFG.is_file():
        try:
            import json

            btc = json.loads(GPU_CFG.read_text(encoding="utf-8")).get("btc_payout", "")
        except Exception:
            pass
    if not btc and state:
        btc = getattr(state, "jam_btc_address", "") or ""

    sessions = _parse_gpu_sessions()
    total_hours = sum(float(s.get("hours", 0)) for s in sessions)
    power_avg = 90
    if sessions:
        power_avg = int(sum(s.get("power_percent", 90) for s in sessions) / len(sessions))

    est = estimate_gpu_earnings(
        hours=total_hours,
        power_percent=power_avg,
        include_electricity=True,
        eur_per_kwh=0.35,
        gpu_watts=270,
    )

    gpu_running = is_gpu_mining_running()
    usb_log = ""
    if MINING_LOG.is_file():
        usb_log = MINING_LOG.read_text(encoding="utf-8", errors="replace")[-500:]

    return {
        "owner": owner_name(state) if state else "David",
        "btc_address": btc,
        "sessions": sessions,
        "total_hours": round(total_hours, 3),
        "total_minutes": round(total_hours * 60, 1),
        "estimate": est,
        "gpu_running": gpu_running,
        "gpu_mode": GPU_CFG.read_text(encoding="utf-8") if GPU_CFG.is_file() else "",
        "usb_cfg": USB_CFG.read_text(encoding="utf-8") if USB_CFG.is_file() else "",
        "usb_log_tail": usb_log,
        "confirmed_btc": None,
        "note": (
            "Geschätzt aus Laufzeit × Hashrate-Richtwert. "
            "Echtes Guthaben prüfen auf unmineable.com oder Blockchain mit deiner BTC-Adresse."
        ),
    }


def write_desktop_pdf(brain: JamBrain | None = None) -> Path:
    from fpdf import FPDF

    data = collect_mining_summary(brain)
    est = data["estimate"]
    stamp = datetime.now().strftime("%d.%m.%Y %H:%M")
    out = desktop_pdf_path()

    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()
    w = pdf.epw

    pdf.set_font(font, "B", 16)
    pdf.cell(0, 10, f"Jam Mining-Bericht - {data['owner']}", new_x="LMARGIN", new_y="NEXT")
    pdf.set_font(font, size=10)
    pdf.multi_cell(
        w,
        5,
        f"Stand: {stamp}  |  GPU laeuft: {'Ja' if data['gpu_running'] else 'Nein'}  |  "
        f"Gesamt-Laufzeit: {data['total_minutes']:.1f} Min ({data['total_hours']:.3f} h)",
    )
    pdf.ln(2)
    pdf.multi_cell(
        w,
        5,
        f"BTC-Adresse (Auszahlung): {data['btc_address'] or '-'}",
    )
    pdf.ln(3)
    pdf.set_font(font, "B", 12)
    pdf.cell(0, 8, "Geschaetzter Verdienst (Brutto / Netto nach Strom)", new_x="LMARGIN", new_y="NEXT")
    pdf.set_font(font, size=10)
    pdf.multi_cell(
        w,
        5,
        f"Brutto: ca. {est['eur_gross']:.4f} EUR ({est['usd_gross']:.4f} USD)  |  "
        f"BTC: ca. {est['btc_gross']:.8f} BTC",
    )
    if est.get("eur_power") is not None and est.get("eur_net") is not None:
        pdf.multi_cell(
            w,
            5,
            f"Stromkosten (geschaetzt): ca. {est['eur_power']:.4f} EUR  |  "
            f"Netto: ca. {est['eur_net']:.4f} EUR",
        )
    pdf.ln(2)
    pdf.set_font(font, "B", 10)
    pdf.multi_cell(w, 5, "WICHTIG: Noch kein Pool-Guthaben automatisch abgefragt.", new_x="LMARGIN", new_y="NEXT")
    pdf.set_font(font, size=9)
    pdf.multi_cell(w, 4, data["note"], new_x="LMARGIN", new_y="NEXT")
    pdf.ln(3)

    pdf.set_font(font, "B", 11)
    pdf.cell(0, 8, "GPU-Sessions (lolMiner / UnMineable)", new_x="LMARGIN", new_y="NEXT")
    pdf.set_font(font, "B", 8)
    cols = (26, 26, 20, 20, 28, 50)
    for w, h in zip(cols, ("Start", "Ende", "Min", "Leist.%", "Algo", "Info")):
        pdf.cell(w, 6, h, border=1)
    pdf.ln()
    pdf.set_font(font, size=8)
    for s in data["sessions"]:
        start = s.get("start")
        end = s.get("end")
        pdf.cell(cols[0], 6, start.strftime("%H:%M:%S") if start else "-", border=1)
        pdf.cell(cols[1], 6, end.strftime("%H:%M:%S") if end else "-", border=1)
        pdf.cell(cols[2], 6, f"{s.get('minutes', 0):.1f}", border=1)
        pdf.cell(cols[3], 6, str(s.get("power_percent", "")), border=1)
        pdf.cell(cols[4], 6, str(s.get("algo", ""))[:10], border=1)
        pdf.cell(cols[5], 6, f"mclk {s.get('mclk', '')}"[:18], border=1)
        pdf.ln()
    pdf.set_x(pdf.l_margin)

    if not data["sessions"]:
        pdf.cell(0, 6, "Keine GPU-Sessions im Log.", new_x="LMARGIN", new_y="NEXT")

    pdf.ln(4)
    pdf.set_font(font, "B", 11)
    pdf.cell(0, 8, "USB-Miner (cgminer / Solo)", new_x="LMARGIN", new_y="NEXT")
    pdf.set_font(font, size=9)
    pdf.multi_cell(
        w,
        4,
        "USB-ASIC-Verdienst ist praktisch 0 EUR (Lotto-Chance). "
        "Siehe Jam-USB-Mining Ordner falls eingerichtet.",
        new_x="LMARGIN",
        new_y="NEXT",
    )

    pdf.ln(2)
    pdf.set_font(font, "B", 10)
    pdf.cell(0, 6, "Pruefen:", new_x="LMARGIN", new_y="NEXT")
    pdf.set_font(font, size=9)
    pdf.multi_cell(
        w,
        4,
        "https://unmineable.com  |  https://blockchain.info/address/" + (data["btc_address"] or ""),
        new_x="LMARGIN",
        new_y="NEXT",
    )

    REPORT_DIR.mkdir(parents=True, exist_ok=True)
    copy = REPORT_DIR / DESKTOP_PDF_NAME
    pdf.output(str(out))
    try:
        import shutil

        shutil.copy2(out, copy)
    except OSError:
        pass
    return out


def hears_mining_report(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if not any(w in h for w in ("mining", "minen", "miner", "btc", "bitcoin")):
        return False
    return any(w in h for w in ("verdienst", "verdient", "pdf", "bericht", "zeig", "wie viel", "guthaben"))


def handle_speech(brain: JamBrain, heard: str) -> str | None:
    if not hears_mining_report(heard):
        return None
    path = write_desktop_pdf(brain)
    data = collect_mining_summary(brain)
    est = data["estimate"]
    try:
        os.startfile(str(path))
    except OSError:
        pass
    return (
        f"Mining-PDF liegt auf dem Desktop: **{path.name}**. "
        f"Laufzeit **{data['total_minutes']:.0f} Min** – geschaetzt "
        f"**~{est['eur_gross']:.4f} €** brutto, **~{est['btc_gross']:.8f} BTC**. "
        f"Echtes Guthaben: unmineable.com mit deiner Adresse prüfen."
    )[:720]
