"""TikTok-Konto verbinden – Standard: @socialmedia.mentor (Social Media Mentor)."""

from __future__ import annotations

import json
import random
import re
import time
import webbrowser
from pathlib import Path

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

DEFAULT_ACCOUNT = "socialmedia.mentor"
LIVE_TAFEL_URL = "http://localhost:8765/tiktok-tafel.html"
BRIDGE_STATUS_PATH = (
    Path(__file__).resolve().parent.parent.parent
    / "minecraft-server"
    / "tiktok-live"
    / "overlay"
    / "status.json"
)

CONNECT_SPEECH: tuple[str, ...] = (
    "Verbunden! Ich bin jetzt mit TikTok @{account} verbunden – {owner}, wir sind ein Team!",
    "TikTok-Link aktiv: @{account}! Jam ist online bei David Story Time!",
    "Ja! @{account} ist mein TikTok – Minecraft LIVE, Bella Italia, alles dabei!",
    "Ich hänge jetzt an @{account}! Wenn David live ist, feier ich mit!",
)

ALREADY_CONNECTED: tuple[str, ...] = (
    "Ich bin schon mit @{account} verbunden! Profil ist offen.",
    "Link steht: @{account} – alles okay!",
)


def normalize_username(raw: str) -> str:
    u = (raw or "").strip().lstrip("@").lower()
    u = re.sub(r"[^a-z0-9._]", "", u)
    return u or DEFAULT_ACCOUNT


def profile_url(account: str | None = None) -> str:
    return f"https://www.tiktok.com/@{normalize_username(account or DEFAULT_ACCOUNT)}"


def live_url(account: str | None = None) -> str:
    """Live-Seite (Profil; bei Live leitet TikTok weiter)."""
    return profile_url(account)


def get_linked_account(state: JamState) -> str:
    if getattr(state, "tiktok_connected", False):
        return normalize_username(getattr(state, "tiktok_account", "") or DEFAULT_ACCOUNT)
    return normalize_username(DEFAULT_ACCOUNT)


def is_connected(state: JamState) -> bool:
    return bool(getattr(state, "tiktok_connected", False))


def _read_bridge_status() -> dict | None:
    try:
        if not BRIDGE_STATUS_PATH.is_file():
            return None
        data = json.loads(BRIDGE_STATUS_PATH.read_text(encoding="utf-8"))
        updated = float(data.get("updated", 0) or 0)
        if time.time() - updated > 180:
            return None
        return data
    except (OSError, json.JSONDecodeError, TypeError, ValueError):
        return None


def bridge_status_text() -> str | None:
    st = _read_bridge_status()
    if not st:
        return None
    if not st.get("connected"):
        return "TikTok-Live-Brücke läuft, wartet auf LIVE."
    likes = int(st.get("likes", 0) or 0)
    goal = int(st.get("goal", 100) or 100)
    user = st.get("tiktok") or DEFAULT_ACCOUNT
    return f"LIVE-Brücke @{user}: {likes}/{goal} Likes in dieser Session."


def hears_connect(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if not any(w in h for w in ("tiktok", "ticktock", "tick tock")):
        if "story.time" not in h and "story time" not in h:
            return False
    if any(
        w in h
        for w in (
            "verbind",
            "connect",
            "link",
            "konto",
            "account",
            "anmelden",
            "einlog",
            "login",
            "koppel",
        )
    ):
        return True
    if "socialmedia" in h.replace(" ", "") or "socialmediamentor" in h.replace(" ", ""):
        return True
    if "david.story" in h.replace(" ", "") or "storytime" in h.replace(" ", ""):
        return True
    if "story time" in h and ("tiktok" in h or "verbind" in h):
        return True
    return False


def parse_account_from_speech(text: str) -> str | None:
    h = text.lower()
    m = re.search(r"@?([a-z0-9._]{3,30})", h.replace("story time", "story.time"))
    if m and "story" in m.group(1):
        return normalize_username(m.group(1))
    if "socialmedia.mentor" in h.replace(" ", "") or "socialmediamentor" in h.replace(" ", ""):
        return DEFAULT_ACCOUNT
    if "david.story.time" in h.replace(" ", ""):
        return "david.story.time"
    return None


def format_connect_bubble(account: str, *, bridge: str | None = None) -> str:
    lines = [
        f"📱 TikTok verbunden",
        f"@{account}",
    ]
    if bridge:
        lines.append(bridge)
    return "\n".join(lines)


def connect_account(
    brain: JamBrain,
    *,
    account: str | None = None,
    user_asked: bool = True,
    open_live_tafel: bool = False,
) -> str:
    """
    Jam „verbindet“ sich mit dem TikTok-Account (gespeichert + Profil im Browser).
    Echte TikTok-API-Login-Session gibt es hier nicht – Verknüpfung + Bella-Live-Brücke.
    """
    from jam import tiktok

    acc = normalize_username(account or parse_account_from_speech("") or DEFAULT_ACCOUNT)
    ok, msg = tiktok.can_open_tiktok(brain.state, user_asked=user_asked)
    if not ok:
        return msg

    was = is_connected(brain.state) and get_linked_account(brain.state) == acc
    brain.state.tiktok_account = acc
    brain.state.tiktok_connected = True
    brain.state.tiktok_connected_at = time.time()
    brain.state.tiktok_connect_count = getattr(brain.state, "tiktok_connect_count", 0) + (
        0 if was else 1
    )
    brain.state.last_tiktok_open = time.time()
    brain.state.last_action = "tiktok_connect"
    brain.state.remember(f"TikTok verbunden: @{acc}")
    brain.state.learn_word("tiktok")
    brain.state.learn_word("storytime")
    brain.add_xp(12)
    brain.save()

    try:
        webbrowser.open(profile_url(acc), new=2)
        if open_live_tafel:
            webbrowser.open(LIVE_TAFEL_URL, new=0)
    except OSError as e:
        return f"TikTok-Verbindung klappt nicht: {e}"

    bridge = bridge_status_text()
    owner = owner_name(brain.state)
    if was:
        line = random.choice(ALREADY_CONNECTED).format(account=acc, owner=owner)
    else:
        line = random.choice(CONNECT_SPEECH).format(account=acc, owner=owner)
    if bridge:
        line += " " + bridge
    elif BRIDGE_STATUS_PATH.is_file():
        line += " Wenn der Minecraft TikTok-Server läuft, bin ich auch LIVE dabei!"
    return line


def handle_connect_speech(brain: JamBrain, heard: str) -> str | None:
    if hears_connect(heard):
        acc = parse_account_from_speech(heard)
        return connect_account(brain, account=acc, user_asked=True)
    return None
