"""
Jam-Seite weltweit online: lokaler Shop + öffentliche URL (ngrok).
"""

from __future__ import annotations

import json
import subprocess
import time
import webbrowser
from datetime import datetime
from pathlib import Path

import requests

from jam.brain import JamBrain, JamState
from jam.master_shop import (
    SHOP_PORT,
    SHOP_ROOT,
    build_master_shop,
    promote_master_shop,
    shop_url,
    start_shop_server,
)
from jam.owner import owner_name

ROOT = Path(__file__).resolve().parent.parent
PUBLIC_URL_FILE = ROOT / "data" / "jam-shop-public-url.txt"
NGROK_PID_FILE = ROOT / "data" / "jam-ngrok.pid"
NGROK_API = "http://127.0.0.1:4040/api/tunnels"


def hears_shop_online(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if any(w in h for w in ("online", "internet", "welt", "global", "öffentlich", "oeffentlich")):
        if any(w in h for w in ("seite", "shop", "verkauf", "website", "link")):
            return True
    if "welt verkauf" in h or "weltweit verkauf" in h:
        return True
    return False


def _save_public_url(url: str) -> None:
    PUBLIC_URL_FILE.parent.mkdir(parents=True, exist_ok=True)
    PUBLIC_URL_FILE.write_text(url + "\n", encoding="utf-8")
    (SHOP_ROOT / "WELT_LINK.txt").write_text(
        f"Jam-Seite weltweit:\n{url}\n\nTeilen: WhatsApp, X, Reddit, Foren\n",
        encoding="utf-8",
    )


def _ngrok_public_url(timeout: float = 25.0) -> str:
    deadline = time.time() + timeout
    while time.time() < deadline:
        try:
            r = requests.get(NGROK_API, timeout=2)
            data = r.json()
            for t in data.get("tunnels", []):
                url = t.get("public_url", "")
                if url.startswith("https://"):
                    return url
        except (requests.RequestException, json.JSONDecodeError, KeyError):
            pass
        time.sleep(1.0)
    return ""


def _stop_old_ngrok() -> None:
    try:
        if NGROK_PID_FILE.is_file():
            pid = int(NGROK_PID_FILE.read_text(encoding="utf-8").strip())
            subprocess.run(
                ["taskkill", "/PID", str(pid), "/F"],
                capture_output=True,
                timeout=10,
            )
            NGROK_PID_FILE.unlink(missing_ok=True)
    except (OSError, ValueError, subprocess.TimeoutExpired):
        pass


def _start_localtunnel() -> tuple[str, str]:
    """Fallback: npx localtunnel (kein ngrok-Account nötig)."""
    try:
        proc = subprocess.Popen(
            ["npx", "-y", "localtunnel", "--port", str(SHOP_PORT)],
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            text=True,
            creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0),
        )
    except FileNotFoundError:
        return "", "Node/npx fehlt für localtunnel"

    NGROK_PID_FILE.parent.mkdir(parents=True, exist_ok=True)
    NGROK_PID_FILE.write_text(str(proc.pid), encoding="utf-8")
    deadline = time.time() + 45.0
    while time.time() < deadline:
        line = proc.stdout.readline() if proc.stdout else ""
        if not line and proc.poll() is not None:
            break
        for part in line.split():
            if part.startswith("https://") and "loca.lt" in part:
                return part.strip(), "localtunnel"
        if "your url is:" in line.lower():
            return line.split(":", 1)[-1].strip(), "localtunnel"
        time.sleep(0.3)
    try:
        proc.kill()
    except OSError:
        pass
    return "", "localtunnel Timeout"


def start_public_tunnel() -> tuple[str, str]:
    """Öffentliche URL: ngrok, sonst localtunnel."""
    _stop_old_ngrok()
    try:
        proc = subprocess.Popen(
            ["ngrok", "http", str(SHOP_PORT), "--log=stdout"],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0),
        )
        NGROK_PID_FILE.parent.mkdir(parents=True, exist_ok=True)
        NGROK_PID_FILE.write_text(str(proc.pid), encoding="utf-8")
        url = _ngrok_public_url()
        if url:
            return url, "ngrok"
        try:
            proc.kill()
        except OSError:
            pass
    except FileNotFoundError:
        pass

    url, via = _start_localtunnel()
    if url:
        return url, via
    return "", "ngrok braucht Authtoken (ngrok.com) oder Netlify-Drop – siehe WELT_HOSTING.txt"


def publish_shop_worldwide(brain: JamBrain, *, open_browser: bool = True) -> str:
    """Shop bauen, Server + öffentlicher Link, Verkauf weltweit."""
    owner = owner_name(brain.state)
    state = brain.state
    state.jam_sell_only_mode = True
    state.jam_world_shop_mode = True
    brain.save()

    _root, n, local = build_master_shop(brain)
    local = start_shop_server()
    public, tunnel_msg = start_public_tunnel()

    if public:
        _save_public_url(public)
        state.jam_master_shop_url = public
        state.jam_master_shop_public_url = public
        state.jam_master_shop_count = n
        state.jam_world_shop_since = time.time()
        brain.save()
        if open_browser:
            try:
                webbrowser.open(public, new=2)
                webbrowser.open(public + "werbung.html", new=2)
            except OSError:
                pass
        brain.state.remember(f"Jam-Shop online: {public[:40]}")
        brain.save()
        return (
            f"{owner}, **Jam-Seite ist weltweit online**! "
            f"{n} Produkte · Link: {public} "
            f"(Lokal: {local}). Tunnel: {tunnel_msg}. "
            f"Teile den Link – PayPal-Kaufen geht weltweit. Jam verkauft nur noch, baut nichts Neues."
        )[:720]

    _write_hosting_fallback(n, local)
    if open_browser:
        promote_master_shop(brain, local, n)
    return (
        f"{owner}, Shop läuft **lokal** ({local}), öffentlicher Tunnel fehlgeschlagen: {tunnel_msg}. "
        f"Siehe {SHOP_ROOT / 'WELT_HOSTING.txt'} – oder ngrok Authtoken setzen. "
        f"{n} Produkte bereit."
    )[:620]


def _write_hosting_fallback(n: int, local: str) -> None:
    (SHOP_ROOT / "WELT_HOSTING.txt").write_text(
        f"Jam-Seite lokal: {local}\n\n"
        f"Weltweit ohne ngrok:\n"
        f"1. Ordner {SHOP_ROOT} auf https://app.netlify.com/drop ziehen\n"
        f"2. Oder ngrok: ngrok config add-authtoken DEIN_TOKEN\n"
        f"   dann: ngrok http {SHOP_PORT}\n\n"
        f"{n} Produkte · PayPal-Buttons funktionieren überall.\n",
        encoding="utf-8",
    )


def get_public_shop_url(state: JamState | None = None) -> str:
    if state and getattr(state, "jam_master_shop_public_url", ""):
        return str(state.jam_master_shop_public_url)
    if PUBLIC_URL_FILE.is_file():
        return PUBLIC_URL_FILE.read_text(encoding="utf-8").strip()
    return ""


def handle_speech(brain: JamBrain, heard: str) -> str | None:
    if not hears_shop_online(heard):
        return None
    return publish_shop_worldwide(brain, open_browser=True)
