"""
Lokale Anmeldedaten (nur auf deinem PC, nie ins Git).

David kann Jam Freigabe geben – Jam füllt Anmeldeformulare per Browser aus.
CAPTCHA, E-Mail-Link und „Veröffentlichen“ bleiben bei dir.
"""

from __future__ import annotations

import json
import os
import re
import subprocess
import time
import webbrowser
from pathlib import Path
from jam.brain import JamBrain, JamState
from jam.owner import owner_name

ROOT = Path(__file__).resolve().parent.parent
CREDENTIALS_FILE = ROOT / "data" / "platform_credentials.local.json"
AUTH_PROFILE_DIR = ROOT / "data" / "platform-playwright-profile"
FIREFOX_HELPER_HTML = ROOT / "data" / "firefox_captcha_helper.html"
GMAIL_INBOX = "https://mail.google.com/mail/u/0/#inbox"
GMAIL_LOGIN = "https://accounts.google.com/signin/v2/identifier?continue=https://mail.google.com"


def hears_auth_grant(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if not any(w in h for w in ("erlaub", "freigabe", "darfst", "verwende", "nutze", "anmelde")):
        return False
    return any(
        w in h
        for w in (
            "passwort",
            "password",
            "anmeldedaten",
            "login daten",
            "logindaten",
            "zugangsdaten",
            "email",
            "e-mail",
            "registrier",
        )
    )


def hears_firefox_captcha(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if "firefox" in h or "mozilla" in h:
        return True
    if "captcha" in h and any(w in h for w in ("email", "e-mail", "mail", "öffne", "oeffne", "firefox")):
        return True
    if any(w in h for w in ("gmail", "posteingang")) and any(
        w in h for w in ("öffne", "oeffne", "firefox", "email", "mail")
    ):
        return True
    return False


def _extract_email_password(text: str) -> tuple[str, str]:
    email = ""
    pwd = ""
    em = re.search(
        r"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})",
        text,
    )
    if em:
        email = em.group(1)
    pm = re.search(
        r"(?:passwort|password)\s+([^\s,;.]+)",
        text,
        re.I,
    )
    if pm:
        pwd = pm.group(1).strip()
    return email, pwd


def save_credentials(
    email: str,
    password: str,
    *,
    granted_by: str = "owner",
) -> Path:
    """Speichert nur lokal (gitignored)."""
    if not email or not password:
        raise ValueError("E-Mail und Passwort fehlen")
    CREDENTIALS_FILE.parent.mkdir(parents=True, exist_ok=True)
    data = {
        "email": email.strip(),
        "password": password,
        "granted_at": time.time(),
        "granted_by": granted_by,
        "note": "Nur auf diesem PC – nicht teilen, nicht committen.",
    }
    CREDENTIALS_FILE.write_text(json.dumps(data, indent=2), encoding="utf-8")
    return CREDENTIALS_FILE


def load_credentials() -> tuple[str, str] | None:
    if not CREDENTIALS_FILE.is_file():
        return None
    try:
        data = json.loads(CREDENTIALS_FILE.read_text(encoding="utf-8"))
        email = str(data.get("email", "")).strip()
        password = str(data.get("password", ""))
        if email and password:
            return email, password
    except (OSError, json.JSONDecodeError, TypeError):
        pass
    return None


def is_auth_granted(state: JamState) -> bool:
    return bool(getattr(state, "jam_owner_auth_granted", False)) and load_credentials() is not None


def grant_owner_auth(
    brain: JamBrain,
    heard: str = "",
    *,
    email: str = "",
    password: str = "",
) -> str:
    owner = owner_name(brain.state)
    if not email or not password:
        email, password = _extract_email_password(heard)
    if not email:
        email = "david.prechtel1986@gmail.com"
    if not password and heard:
        m = re.search(r"\b(Ibel\d+\??)\b", heard, re.I)
        if m:
            password = m.group(1)

    if not password:
        return (
            f"{owner}, ich brauche E-Mail und Passwort – oder sag: "
            f"„Jam, Erlaubnis: email@… Passwort …“"
        )

    path = save_credentials(email, password)
    state = brain.state
    state.jam_owner_auth_granted = True
    state.jam_owner_auth_granted_at = time.time()
    state.jam_platform_signup_mode = True
    state.remember("David gab Anmelde-Freigabe (lokal gespeichert)")
    brain.add_xp(5)
    brain.save()

    return (
        f"{owner}, Freigabe gespeichert (nur auf diesem PC: {path.name}). "
        f"Ich fülle Anmeldeformulare auf Verkaufs-Plattformen aus – "
        f"CAPTCHA, E-Mail-Bestätigung und „Publish“ musst du noch selbst klicken. "
        f"Sag „Jam, Firefox für CAPTCHA“ oder „überall registrieren“."
    )[:520]


def _firefox_exe() -> Path | None:
    candidates: list[Path] = []
    for key in ("ProgramFiles", "ProgramFiles(x86)"):
        base = os.environ.get(key, "")
        if base:
            candidates.append(Path(base) / "Mozilla Firefox" / "firefox.exe")
    local = Path.home() / "AppData" / "Local" / "Mozilla Firefox" / "firefox.exe"
    candidates.append(local)
    for p in candidates:
        if p.is_file():
            return p
    return None


def open_in_firefox(url: str, *, new_window: bool = False) -> bool:
    """Immer Firefox – getrennt von Edge/Playwright für CAPTCHA & E-Mail."""
    exe = _firefox_exe()
    if not exe:
        try:
            webbrowser.get("firefox").open(url, new=1 if new_window else 2)
            return True
        except webbrowser.Error:
            webbrowser.open(url, new=2)
            return False
    args = [str(exe)]
    if new_window:
        args.append("-new-window")
    else:
        args.append("-new-tab")
    args.append(url)
    try:
        subprocess.Popen(
            args,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            close_fds=True,
        )
        return True
    except OSError:
        return False


def _write_firefox_helper_page(email: str, links: list[tuple[str, str]]) -> Path:
    rows = "\n".join(
        f'<li><a href="{u}" target="_blank">{n}</a> – Anmeldung / CAPTCHA</li>'
        for n, u in links
    )
    html = f"""<!DOCTYPE html>
<html lang="de"><head><meta charset="utf-8">
<title>Jam – CAPTCHA & E-Mail</title>
<style>
body {{ font-family: system-ui; max-width: 720px; margin: 2rem auto; padding: 0 1rem; }}
h1 {{ color: #1a5; }} .email {{ background: #eef; padding: 12px; border-radius: 8px; }}
ul a {{ font-size: 1.05rem; }}
</style></head><body>
<h1>Jam: CAPTCHA & E-Mail (Firefox)</h1>
<p class="email"><strong>Deine E-Mail (überall gleich):</strong><br>{email}</p>
<p>Edge/Playwright füllt Formulare – <strong>hier in Firefox</strong> CAPTCHA lösen und E-Mail bestätigen.</p>
<p><a href="{GMAIL_INBOX}">Gmail Posteingang öffnen</a> ·
<a href="{GMAIL_LOGIN}">Gmail Login</a></p>
<h2>Plattform-Anmeldung</h2>
<ul>{rows}</ul>
<p><small>Passwort: wie in Jam gespeichert (nicht auf dieser Seite).</small></p>
</body></html>"""
    FIREFOX_HELPER_HTML.parent.mkdir(parents=True, exist_ok=True)
    FIREFOX_HELPER_HTML.write_text(html, encoding="utf-8")
    return FIREFOX_HELPER_HTML


def open_firefox_captcha_and_email(
    brain: JamBrain,
    *,
    platform: str | None = None,
    signup_url: str | None = None,
) -> str:
    """
    Separater Firefox: Hilfsseite + Gmail + Anmeldeseite(n).
    Gleiche E-Mail wie in den Credentials.
    """
    from jam.paypal_donate import PAYPAL_EMAIL

    creds = load_credentials()
    email = creds[0] if creds else PAYPAL_EMAIL

    from jam.platform_signup import PLATFORMS

    links: list[tuple[str, str]] = []
    if platform and signup_url:
        links.append((platform, signup_url))
    else:
        for name, su, _sell, _hint in PLATFORMS:
            if name != "PayPal Business":
                links.append((name, su))

    helper = _write_firefox_helper_page(email, links)
    opened: list[str] = []

    if open_in_firefox(helper.as_uri(), new_window=True):
        opened.append("Jam-Hilfsseite")
    time.sleep(0.6)
    if open_in_firefox(GMAIL_INBOX):
        opened.append("Gmail Posteingang")
    time.sleep(0.5)

    targets = links if platform else links[:4]
    for name, url in targets:
        if open_in_firefox(url):
            opened.append(name)
        time.sleep(0.45)

    state = brain.state
    state.last_firefox_captcha_at = time.time()
    state.remember("Firefox für CAPTCHA + E-Mail geöffnet")
    brain.save()

    owner = owner_name(state)
    return (
        f"{owner}, **Firefox ist separat offen** (nicht Edge)! "
        f"E-Mail überall: **{email}**. "
        f"Tabs: {', '.join(opened)}. "
        f"Löse CAPTCHA in den Plattform-Tabs, Bestätigungs-Mail in **Gmail**. "
        f"Hilfsseite: data/firefox_captcha_helper.html"
    )[:520]


def _playwright_ok() -> bool:
    try:
        import playwright  # noqa: F401

        return True
    except ImportError:
        return False


def _fill_login_form(page, email: str, password: str) -> list[str]:
    done: list[str] = []
    page.wait_for_timeout(1500)

    email_selectors = [
        'input[type="email"]',
        'input[name*="email" i]',
        'input[id*="email" i]',
        'input[autocomplete="email"]',
        'input[placeholder*="mail" i]',
    ]
    for sel in email_selectors:
        try:
            loc = page.locator(sel).first
            if loc.count() and loc.is_visible(timeout=800):
                loc.fill(email, timeout=5000)
                done.append("E-Mail")
                break
        except Exception:
            continue

    pwd_selectors = [
        'input[type="password"]',
        'input[name*="password" i]',
        'input[id*="password" i]',
    ]
    for sel in pwd_selectors:
        try:
            loc = page.locator(sel).first
            if loc.count() and loc.is_visible(timeout=800):
                loc.fill(password, timeout=5000)
                done.append("Passwort")
                break
        except Exception:
            continue

    for label in (
        "Sign up",
        "Signup",
        "Register",
        "Registrieren",
        "Create account",
        "Konto erstellen",
        "Weiter",
        "Continue",
        "Log in",
        "Login",
        "Anmelden",
    ):
        try:
            btn = page.get_by_role("button", name=re.compile(label, re.I)).first
            if btn.is_visible(timeout=600):
                btn.click(timeout=3000)
                done.append(f"Klick:{label}")
                page.wait_for_timeout(2000)
                break
        except Exception:
            try:
                link = page.get_by_role("link", name=re.compile(label, re.I)).first
                if link.is_visible(timeout=500):
                    link.click(timeout=3000)
                    done.append(f"Link:{label}")
                    page.wait_for_timeout(2000)
                    break
            except Exception:
                pass

    return done


def attempt_browser_signup(
    platform_name: str,
    signup_url: str,
    email: str,
    password: str,
    *,
    headless: bool = False,
    keep_open_sec: float = 8.0,
) -> tuple[str, list[str]]:
    """Playwright: Seite öffnen, Felder ausfüllen – kein Garant für erfolgreiche Registrierung."""
    if not _playwright_ok():
        return "Playwright fehlt (pip install playwright && playwright install msedge)", []

    from playwright.sync_api import sync_playwright

    steps: list[str] = []
    try:
        from jam.jam_browser_auto import get_automation_profile_dir

        profile_dir = get_automation_profile_dir()
    except Exception:
        profile_dir = AUTH_PROFILE_DIR
    profile_dir.mkdir(parents=True, exist_ok=True)

    try:
        with sync_playwright() as p:
            try:
                context = p.chromium.launch_persistent_context(
                    str(profile_dir),
                    channel="msedge",
                    headless=headless,
                    viewport={"width": 1280, "height": 860},
                    locale="de-DE",
                )
            except Exception:
                context = p.chromium.launch_persistent_context(
                    str(profile_dir),
                    headless=headless,
                    viewport={"width": 1280, "height": 860},
                    locale="de-DE",
                )

            page = context.pages[0] if context.pages else context.new_page()
            page.goto(signup_url, wait_until="domcontentloaded", timeout=60_000)
            steps.append(f"{platform_name}: Seite geladen")
            filled = _fill_login_form(page, email, password)
            steps.extend(filled)

            try:
                shot = ROOT / "data" / f"signup-{platform_name.replace(' ', '_').lower()}.png"
                page.screenshot(path=str(shot), full_page=False)
                steps.append("Screenshot")
            except Exception:
                pass

            page.bring_to_front()
            page.wait_for_timeout(int(keep_open_sec * 1000))
            # Profil bleibt gespeichert – nächstes Mal evtl. schon eingeloggt
            context.close()

        return "OK", steps
    except Exception as e:
        return str(e)[:200], steps


def run_register_all_platforms(brain: JamBrain, *, user_initiated: bool = True) -> str:
    """Alle Verkaufs-Plattformen: Browser-Anmeldung versuchen."""
    from jam.platform_signup import PLATFORMS, enable_platform_signup_sell, run_platform_signup_and_sell

    creds = load_credentials()
    if not creds:
        return grant_owner_auth(brain, heard="")
    email, password = creds
    owner = owner_name(brain.state)
    brain.state.jam_owner_auth_granted = True
    enable_platform_signup_sell(brain, hours=72.0)

    parts: list[str] = [
        f"{owner}, ich registriere mit deiner Freigabe auf allen Verkaufs-Plattformen "
        f"(E-Mail {email[:3]}…). CAPTCHA & E-Mail-Link: du!"
    ]

    for name, signup_url, sell_url, _hint in PLATFORMS:
        if name == "PayPal Business":
            continue
        status, steps = attempt_browser_signup(
            name, signup_url, email, password, keep_open_sec=6.0 if user_initiated else 4.0
        )
        open_firefox_captcha_and_email(
            brain, platform=name, signup_url=signup_url
        )
        parts.append(f"{name}: {status} ({', '.join(steps) or '—'})"[:120])
        time.sleep(1.5)
        brain.state.last_platform_signup_at = 0.0
        try:
            run_platform_signup_and_sell(brain, user_initiated=False)
        except Exception:
            pass

    brain.state.last_action = "register_all_platforms"
    brain.save()
    return " | ".join(parts)[:700]


def handle_speech(brain: JamBrain, heard: str) -> str | None:
    h = heard.lower()
    if hears_firefox_captcha(heard):
        return open_firefox_captcha_and_email(brain)
    if hears_auth_grant(heard):
        return grant_owner_auth(brain, heard=heard)
    if is_auth_granted(brain.state) or load_credentials():
        if any(
            w in h
            for w in (
                "überall registrier",
                "ueberall registrier",
                "alle plattform",
                "registrier überall",
                "anmelden überall",
                "everywhere register",
            )
        ):
            return run_register_all_platforms(brain, user_initiated=True)
    return None
