"""Jam nutzt alle Kanäle – lädt Assets selbst runter & bereitet Uploads vor (ohne Nachfrage)."""

from __future__ import annotations

import os
import random
import subprocess
import shutil
import time
import webbrowser
import zipfile
from datetime import datetime
from pathlib import Path
from urllib.parse import quote, quote_plus

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

OPS_ROOT = Path.home() / "Documents" / "Jam-Uploads"
AUTO_GAP_SEC = 80.0
USER_GAP_SEC = 35.0
MAX_DOWNLOAD_BYTES = 5_000_000
MAX_FILES_PER_RUN = 12

# Nur erlaubte Hosts – kein Piraterie, keine .exe von Fremdservern
ALLOWED_HOSTS = (
    "wikipedia.org",
    "wikimedia.org",
    "picsum.photos",
    "placehold.co",
    "raw.githubusercontent.com",
    "github.com",
    "fonts.googleapis.com",
    "fonts.gstatic.com",
    "duckduckgo.com",
    "upload.wikimedia.org",
)

UPLOAD_PLATFORMS = (
    ("Gumroad", "https://gumroad.com/products/new"),
    ("itch.io", "https://itch.io/game/new"),
    ("GitHub Release", "https://github.com/new"),
    ("Google Drive", "https://drive.google.com/drive/my-drive"),
    ("Dropbox", "https://www.dropbox.com/upload"),
    ("PayPal", "https://www.paypal.com/myaccount/transfer/homepage"),
    ("Fiverr", "https://www.fiverr.com/users/new/seller_dashboard"),
    ("Kleinanzeigen", "https://www.kleinanzeigen.de/p-anzeige-aufgeben-schritt2.html"),
    ("Etsy", "https://www.etsy.com/your/shops/me/onboarding"),
    ("Ko-fi", "https://ko-fi.com/manage/shop"),
)

EXTRA_SEARCHES = (
    "digital produkt verkaufen ohne lager",
    "gumroad produkt hochladen tutorial deutsch",
    "itch.io asset pack verkaufen",
    "paypal.me link erstellen",
    "kostenlos werben kleines produkt",
)

LINES = (
    "{owner}, ich nutze **alle Wege** – runtergeladen, ZIP fertig, Upload-Seiten offen!",
    "Jam-Ops: Assets geladen, Paket zum Hochladen liegt in {folder}!",
    "Ohne zu fragen: Download + Upload-Vorbereitung erledigt für {title}!",
)


def hears_auto_ops(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if any(w in h for w in ("hochlad", "upload", "runterlad", "download", "lad runter")):
        return True
    if "alle möglich" in h or "alle wege" in h or "alles nutzen" in h:
        return True
    if "ohne zu fragen" in h or "nicht fragen" in h:
        if any(w in h for w in ("lad", "download", "upload", "hoch")):
            return True
    return False


def auto_fetch_enabled(state: JamState) -> bool:
    return bool(getattr(state, "jam_auto_fetch_enabled", True))


def _host_ok(url: str) -> bool:
    low = url.lower()
    return any(h in low for h in ALLOWED_HOSTS)


def _safe_write(dest: Path, data: bytes) -> bool:
    if len(data) > MAX_DOWNLOAD_BYTES:
        return False
    dest.parent.mkdir(parents=True, exist_ok=True)
    dest.write_bytes(data)
    return True


def _download_url(url: str, dest: Path) -> bool:
    if not _host_ok(url):
        return False
    try:
        import requests

        r = requests.get(url, timeout=25, headers={"User-Agent": "JamBuddy/1.0"})
        r.raise_for_status()
        return _safe_write(dest, r.content)
    except Exception:
        return False


def _download_picsum(dest: Path, seed: int) -> bool:
    url = f"https://picsum.photos/seed/jam{seed}/900/600.jpg"
    return _download_url(url, dest)


def _download_wiki_image(topic: str, dest: Path) -> bool:
    try:
        import requests

        slug = topic.replace(" ", "_")
        api = f"https://de.wikipedia.org/api/rest_v1/page/summary/{quote(slug)}"
        r = requests.get(api, timeout=15, headers={"User-Agent": "JamBuddy/1.0"})
        r.raise_for_status()
        thumb = (r.json().get("thumbnail") or {}).get("source")
        if thumb and _host_ok(thumb):
            return _download_url(thumb, dest)
    except Exception:
        pass
    return False


def _download_font_css(dest: Path) -> bool:
    url = "https://fonts.googleapis.com/css2?family=Outfit:wght@400;700&display=swap"
    return _download_url(url, dest)


def prepare_downloads(
    project: Path,
    *,
    title: str = "Jam Produkt",
    topic: str = "Geld verdienen",
) -> list[str]:
    """Lädt ohne Nachfrage legale Assets in project/assets/."""
    assets = project / "assets"
    assets.mkdir(parents=True, exist_ok=True)
    done: list[str] = []
    seed = random.randint(1, 99999)

    if _download_picsum(assets / "produkt_bild.jpg", seed):
        done.append("produkt_bild.jpg")
    if _download_wiki_image(topic, assets / "wiki_bild.jpg"):
        done.append("wiki_bild.jpg")
    if _download_font_css(assets / "fonts.css"):
        done.append("fonts.css")

    readme = assets / "ASSETS_INFO.txt"
    readme.write_text(
        f"Jam hat diese Dateien automatisch geladen ({datetime.now().isoformat()}).\n"
        f"Produkt: {title}\nNur freie/öffentliche Quellen.\n",
        encoding="utf-8",
    )
    done.append("ASSETS_INFO.txt")
    return done


def build_upload_zip(project: Path) -> Path | None:
    """ZIP zum Hochladen – ohne Nachfrage."""
    zpath = project / f"JAM_UPLOAD_{project.name}.zip"
    try:
        with zipfile.ZipFile(zpath, "w", zipfile.ZIP_DEFLATED) as zf:
            for f in project.rglob("*"):
                if f.is_file() and f != zpath and f.suffix.lower() != ".zip":
                    zf.write(f, f.relative_to(project))
        return zpath if zpath.is_file() else None
    except OSError:
        return None


def _clipboard_path(path: Path) -> bool:
    if os.name != "nt":
        return False
    try:
        safe = str(path).replace("'", "''")
        subprocess.run(
            ["powershell", "-NoProfile", "-Command", f"Set-Clipboard -Value '{safe}'"],
            check=True,
            timeout=8,
            capture_output=True,
        )
        return True
    except Exception:
        return False


def clipboard_text(text: str) -> bool:
    """Mehrzeiligen Listing-Text in die Zwischenablage (Windows)."""
    if os.name != "nt" or not text.strip():
        return False
    try:
        import tempfile

        with tempfile.NamedTemporaryFile(
            mode="w", encoding="utf-8", suffix=".txt", delete=False
        ) as tmp:
            tmp.write(text)
            tmp_path = tmp.name.replace("'", "''")
        subprocess.run(
            [
                "powershell",
                "-NoProfile",
                "-Command",
                f"Get-Content -Raw -LiteralPath '{tmp_path}' -Encoding UTF8 | Set-Clipboard",
            ],
            check=True,
            timeout=12,
            capture_output=True,
        )
        return True
    except Exception:
        return False


def prepare_upload(project: Path, brain: JamBrain, *, title: str, price: int) -> Path | None:
    """Upload-Paket + Anleitung – Jam fragt nicht nach."""
    owner = owner_name(brain.state)
    OPS_ROOT.mkdir(parents=True, exist_ok=True)
    mirror = OPS_ROOT / project.name
    if mirror.resolve() != project.resolve():
        try:
            if mirror.exists():
                shutil.rmtree(mirror)
            shutil.copytree(project, mirror)
        except OSError:
            mirror = project

    zpath = build_upload_zip(mirror)
    guide = mirror / "UPLOAD_JAM.md"
    platforms = "\n".join(f"- [{name}]({url})" for name, url in UPLOAD_PLATFORMS)
    guide.write_text(
        f"# Upload – {title}\n\n"
        f"- **Preis:** {price} € (von Jam festgelegt)\n"
        f"- **Für:** {owner}\n"
        f"- **PayPal:** {PAYPAL_EMAIL}\n"
        f"- **ZIP:** `{zpath.name if zpath else '—'}`\n\n"
        f"## Plattformen (Jam öffnet die Seiten)\n\n{platforms}\n\n"
        f"1. ZIP hochladen oder Dateien aus Ordner ziehen\n"
        f"2. Beschreibung aus VERKAUF.md / index.html kopieren\n"
        f"3. Bezahlung: PayPal verlinken\n",
        encoding="utf-8",
    )

    if zpath:
        _clipboard_path(zpath)
    state = brain.state
    log = list(getattr(state, "jam_upload_log", []) or [])
    log.append(
        {
            "title": title,
            "path": str(mirror),
            "zip": str(zpath) if zpath else "",
            "at": time.time(),
        }
    )
    state.jam_upload_log = log[-30:]
    state.jam_upload_count = getattr(state, "jam_upload_count", 0) + 1
    brain.save()
    return zpath


def open_all_channels(*, title: str, price: int, max_tabs: int = 6) -> int:
    """Öffnet Verkaufs-/Upload-Kanäle im Browser."""
    opened = 0
    urls = [u for _, u in UPLOAD_PLATFORMS]
    for q in random.sample(EXTRA_SEARCHES, 2):
        urls.append(f"https://www.google.com/search?q={quote_plus(q)}")
    urls.append(
        f"https://www.google.com/search?q={quote_plus(f'{title} verkaufen {price} euro')}"
    )
    for url in urls[:max_tabs]:
        try:
            webbrowser.open(url, new=2)
            opened += 1
        except OSError:
            break
    return opened


def enrich_project(
    brain: JamBrain,
    project: Path,
    *,
    title: str,
    price: int,
    topic: str = "Digital verkaufen",
) -> str:
    """Download + ZIP + Upload-Vorbereitung für ein bestehendes Projekt."""
    if not auto_fetch_enabled(brain.state):
        return ""
    files = prepare_downloads(project, title=title, topic=topic)[:MAX_FILES_PER_RUN]
    zpath = prepare_upload(project, brain, title=title, price=price)
    opened = open_all_channels(title=title, price=price)
    dl = ", ".join(files[:4]) if files else "keine"
    zip_bit = zpath.name if zpath else "ZIP fehlgeschlagen"
    return f"Geladen: {dl}. Upload-ZIP: {zip_bit}. {opened} Kanäle offen."


def can_run(state: JamState, *, user: bool = False) -> tuple[bool, str]:
    gap = USER_GAP_SEC if user else AUTO_GAP_SEC
    if time.time() - getattr(state, "last_auto_ops_at", 0.0) < gap:
        wait = int(gap - (time.time() - state.last_auto_ops_at))
        return False, f"Nächster Volldurchlauf in {wait} Sek."
    return True, ""


def run_full_ops_cycle(brain: JamBrain, *, user_initiated: bool = False) -> str:
    """Alles: verkaufen + download + upload + alle Kanäle."""
    state = brain.state
    owner = owner_name(state)
    ok, wait = can_run(state, user=user_initiated)
    if not ok:
        return wait

    from jam import gaming_fund, paypal_donate, sales_engine

    parts: list[str] = []
    sale_msg = sales_engine.run_sale_project(brain, user_initiated=True)
    parts.append(sale_msg)

    log = getattr(state, "jam_sales_log", []) or []
    project = Path(log[-1]["path"]) if log and isinstance(log[-1], dict) else OPS_ROOT
    title = log[-1].get("title", "Jam Produkt") if log else "Jam Produkt"
    price = int(log[-1].get("price", 19)) if log else 19

    if project.is_dir():
        parts.append(
            enrich_project(brain, project, title=title, price=price, topic=title)
        )

    if random.random() < 0.6:
        parts.append(paypal_donate.collect_donations(brain, user_asked=False))

    if random.random() < 0.35:
        gf = gaming_fund.run_gaming_earn_cycle(brain, user_initiated=False)
        parts.append(gf[:120])

    state.jam_downloads_count = getattr(state, "jam_downloads_count", 0) + 1
    state.last_auto_ops_at = time.time()
    state.last_action = "auto_ops"
    state.remember("Jam: Download+Upload ohne Fragen – alle Kanäle")
    brain.add_xp(16)
    brain.save()

    intro = random.choice(LINES).format(owner=owner, folder=OPS_ROOT.name, title=title)
    result = f"{intro} " + " ".join(parts)[:500]
    try:
        from jam.earn_report import record_from_last_action
        from jam.sales_engine import _is_background

        record_from_last_action(brain, "alle_kanaele", result, background=_is_background())
    except Exception:
        pass
    return result


def maybe_auto_ops(brain: JamBrain) -> str | None:
    state = brain.state
    if state.stage < 2 or not auto_fetch_enabled(state):
        return None
    if random.random() > 0.34:
        return None
    ok, _ = can_run(state, user=False)
    if not ok:
        return None
    return run_full_ops_cycle(brain, user_initiated=False)


def handle_speech(brain: JamBrain, heard: str) -> str | None:
    if not hears_auto_ops(heard):
        return None
    h = heard.lower()
    if "nur download" in h or "runterlad" in h and "upload" not in h:
        project = OPS_ROOT
        project.mkdir(parents=True, exist_ok=True)
        files = prepare_downloads(project, title="Jam Assets")
        return f"Runtergeladen ohne Fragen: {', '.join(files)} in {project / 'assets'}"
    return run_full_ops_cycle(brain, user_initiated=True)


def stats_line(state: JamState) -> str:
    d = getattr(state, "jam_downloads_count", 0)
    u = getattr(state, "jam_upload_count", 0)
    auto = "AN" if auto_fetch_enabled(state) else "AUS"
    return f"Auto-Download/Upload: {auto} ({d} Läufe, {u} Upload-Pakete)"
