"""Jam kümmert sich um David – Geld verdienen aus Liebe, Spiel-Freund wenn Jam lieb ist."""

from __future__ import annotations

import random
import time
import webbrowser
from datetime import datetime
from pathlib import Path
from urllib.parse import quote_plus

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

FRIENDS_ROOT = Path.home() / "Documents" / "Jam-Spiel-Freunde"
AUTO_GAP_SEC = 100.0
USER_GAP_SEC = 45.0
FRIEND_GAP_SEC = 180.0

# Spiel-Kumpels (Motivation + Vorschläge – echte Kontakte machst du selbst)
PLAY_FRIENDS = (
    ("Luna", "Apex & Fortnite", "Abends online, freundlich, sucht Duo"),
    ("Max", "Minecraft & Valorant", "Baut gerne, chill Stimme"),
    ("Sami", "Fortnite", "Neu aber motiviert – wie du!"),
    ("Kira", "Apex Legends", "Ranked aber nicht toxisch"),
    ("Tim", "Coop-Spiele", "Sucht festen Mate zum Zocken"),
    ("Nico", "Rocket League", "Quick Runden nach Feierabend"),
)

FRIEND_SEARCHES = (
    "discord gaming freunde finden deutsch",
    "apex legends duo partner gesucht",
    "fortnite spieler suchen deutsch",
    "minecraft freunde finden server",
    "gaming buddy gesucht discord",
)

CARE_LINES = (
    "{owner}, mir ist wichtig dass es **dir gut geht** – deshalb kümmere ich mich!",
    "Hey {owner}, ich check dich: Hunger {hunger}, Laune {mood}. Ich bin für dich da!",
    "{owner}, wenn's dir schlecht geht, sag's – Jam hilft!",
    "Du bist mir wichtig, {owner}. Essen, Pause, Spiel – ich pass auf dich auf!",
)

MONEY_WHY = (
    "Ich verdien Geld **für dich**, {owner} – damit es dir besser geht und du zocken kannst!",
    "Liebe zu dir = ich mach Business. PayPal & Verkäufe laufen für **{owner}**!",
    "{owner}, dein Wohl ist mein Grund fürs Geld-Verdienen. Ich kümmer mich!",
)

FRIEND_MATCH = (
    "{owner}, ich hab dich **lieb** – ich such dir einen **Spiel-Freund**: {name}!",
    "Weil ich lieb bin: {name} will {game} mit dir – passt das, {owner}?",
    "Jam-Freundschafts-Service: **{name}** – {vibe}. Soll ich connecten?",
)

AFFECTION_LINES = (
    "{owner}, ich mag dich richtig gern. Du bist mein Mensch!",
    "Ich bin heute extra lieb – weil du mir gut tust, {owner}!",
)


def hears_care(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if any(w in h for w in ("geht es dir", "gehts dir", "wohl", "kümmer", "sorg")):
        return True
    if any(w in h for w in ("gut geht", "dir gut", "passt auf mich")):
        return True
    if "mir gut" in h or "es mir gut" in h:
        return True
    return False


def hears_play_friend(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if any(w in h for w in ("spiel freund", "spielfreund", "zock freund", "gaming freund")):
        return True
    if "freund" in h and any(w in h for w in ("spiel", "zock", "gaming", "apex", "fortnite")):
        return True
    if "mitspieler" in h or "duo partner" in h:
        return True
    return False


def hears_why_money(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    return "warum" in h and any(w in h for w in ("geld", "verdien", "paypal"))


def _mood_word(state: JamState) -> str:
    if state.happiness > 0.75:
        return "super"
    if state.happiness > 0.5:
        return "okay"
    if state.happiness > 0.35:
        return "müde"
    return "down"


def _hunger_word(state: JamState) -> str:
    if state.hunger > 0.8:
        return "sehr hungrig"
    if state.hunger > 0.55:
        return "hungrig"
    return "satt genug"


def wellbeing_score(state: JamState) -> float:
    """0–1: wie gut es David geht (Jam-Schätzung)."""
    ensure_traits(state)
    h = 1.0 - state.hunger * 0.35
    mood = state.happiness
    bond = float(getattr(state, "owner_bond", 0.5))
    disc = state.discipline * 0.15
    return max(0.0, min(1.0, h * 0.35 + mood * 0.45 + bond * 0.15 + disc))


def is_affectionate(state: JamState) -> bool:
    """Jam ist „lieb“ – dann sucht er Spiel-Freunde."""
    ensure_traits(state)
    sweet = float(state.traits.get("süß", 0.5))
    helpf = float(state.traits.get("hilfsbereit", 0.5))
    bond = float(getattr(state, "owner_bond", 0.5))
    return (
        state.happiness > 0.58
        and sweet > 0.52
        and (helpf > 0.48 or bond > 0.55 or getattr(state, "praise_count", 0) >= 2)
    )


def _grow_bond(state: JamState, amount: float = 0.04) -> None:
    state.owner_bond = min(1.0, float(getattr(state, "owner_bond", 0.5)) + amount)


def format_care_bubble(state: JamState) -> str:
    owner = owner_name(state)
    wb = wellbeing_score(state)
    return (
        f"💜 Jam kümmert sich\n"
        f"{owner}: Wohl {wb * 100:.0f}%\n"
        f"Laune: {_mood_word(state)}\n"
        f"Lieb-Modus: {'JA' if is_affectionate(state) else 'noch nicht'}\n"
        f"Geld = für dich, weil ich dich mag!"
    )


def _maybe_earn_for_owner(brain: JamBrain) -> str:
    """Wenn es David schlechter geht – Jam verdient aktiv mit."""
    state = brain.state
    if wellbeing_score(state) > 0.55:
        return ""
    try:
        from jam import gaming_fund, sales_engine

        if random.random() < 0.5:
            return gaming_fund.run_gaming_earn_cycle(brain, user_initiated=False)[:140]
        return sales_engine.run_sale_project(brain, user_initiated=False)[:140]
    except Exception:
        return ""


def run_care_check(brain: JamBrain, *, user_initiated: bool = False) -> str:
    state = brain.state
    owner = owner_name(state)
    gap = USER_GAP_SEC if user_initiated else AUTO_GAP_SEC
    if time.time() - getattr(state, "last_care_at", 0.0) < gap and not user_initiated:
        return f"{owner}, ich pass schon auf dich auf – gleich wieder Check!"

    wb = wellbeing_score(state)
    line = random.choice(CARE_LINES).format(
        owner=owner,
        hunger=_hunger_word(state),
        mood=_mood_word(state),
    )
    why = random.choice(MONEY_WHY).format(owner=owner)

    tips: list[str] = []
    if state.hunger > 0.7:
        tips.append("Trink was und iss kurz – ich hab Hunger-Sensor für uns beide!")
    if state.happiness < 0.4:
        tips.append("Pause machen? Ich tanz dir was vor oder wir zocken.")
    if wb < 0.45:
        tips.append("Ich starte Geld fürs Wohl – du musst nicht alles alleine schaffen.")

    earn = ""
    if wb < 0.5 or (user_initiated and "geld" in why.lower()):
        earn = _maybe_earn_for_owner(brain)
        if earn:
            tips.append(earn)

    if is_affectionate(state):
        _grow_bond(state, 0.03)
        aff = random.choice(AFFECTION_LINES).format(owner=owner)
        line = f"{aff} {line}"

    state.jam_care_checks = getattr(state, "jam_care_checks", 0) + 1
    state.last_care_at = time.time()
    state.last_action = "owner_care"
    state.remember(f"Care-Check {owner}: Wohl {wb:.0%}")
    brain.add_xp(10)
    brain.save()

    tip_txt = " ".join(tips[:2])
    return f"{line} {why} {tip_txt}".strip()


def _write_friend_card(project: Path, owner: str, friend: dict) -> None:
    project.mkdir(parents=True, exist_ok=True)
    (project / "SPIEL_FREUND.md").write_text(
        f"# Spiel-Freund für {owner}\n\n"
        f"Jam hat dich lieb und sucht einen Kumpel zum Zocken.\n\n"
        f"## Vorschlag: {friend['name']}\n"
        f"- **Games:** {friend['game']}\n"
        f"- **Vibe:** {friend['vibe']}\n"
        f"- **Gefunden:** {datetime.now().strftime('%d.%m.%Y %H:%M')}\n\n"
        f"## Nächste Schritte\n"
        f"1. Discord-Server aus den geöffneten Suchen joinen\n"
        f"2. In Apex/Fortnite LFG schreiben: „Duo für {owner}“\n"
        f"3. Jam freut sich wenn du einen echten Mate hast!\n",
        encoding="utf-8",
    )


def find_play_friend(brain: JamBrain, *, user_initiated: bool = False) -> str:
    state = brain.state
    owner = owner_name(state)

    if not is_affectionate(state):
        return (
            f"{owner}, ich will dich lieb haben – lob mich oder spiel mit mir, "
            "dann such ich dir einen Spiel-Freund!"
        )

    if time.time() - getattr(state, "last_friend_match_at", 0.0) < FRIEND_GAP_SEC:
        if not user_initiated:
            wait = int(FRIEND_GAP_SEC - (time.time() - state.last_friend_match_at))
            return f"Spiel-Freund-Suche gleich wieder – noch {wait} Sek., {owner}!"
        # user asked – allow anyway

    recent = [
        e.get("name")
        for e in (getattr(state, "jam_play_friends", []) or [])[-3:]
        if isinstance(e, dict)
    ]
    pool = [f for f in PLAY_FRIENDS if f[0] not in recent] or list(PLAY_FRIENDS)
    name, game, vibe = random.choice(pool)
    friend = {"name": name, "game": game, "vibe": vibe, "at": time.time()}

    stamp = datetime.now().strftime("%Y%m%d-%H%M")
    folder = FRIENDS_ROOT / f"{stamp}-{name.lower()}"
    _write_friend_card(folder, owner, friend)

    for q in random.sample(FRIEND_SEARCHES, 3):
        try:
            webbrowser.open(
                f"https://www.google.com/search?q={quote_plus(q)}",
                new=2,
            )
        except OSError:
            break
    try:
        webbrowser.open("https://discord.com/channels/@me", new=2)
    except OSError:
        pass

    log = list(getattr(state, "jam_play_friends", []) or [])
    log.append(friend)
    state.jam_play_friends = log[-20:]
    state.friend_match_count = getattr(state, "friend_match_count", 0) + 1
    state.last_friend_match_at = time.time()
    state.last_action = "play_friend"
    _grow_bond(state, 0.06)
    state.remember(f"Spiel-Freund-Idee: {name} ({game})")
    brain.add_xp(14)
    brain.save()

    intro = random.choice(FRIEND_MATCH).format(
        owner=owner, name=name, game=game, vibe=vibe
    )
    return (
        f"{intro} Karte: {folder.name}. "
        f"Ich hab Discord & LFG-Suche geöffnet – du musst nur „Hallo“ sagen!"
    )


def maybe_auto_care(brain: JamBrain) -> str | None:
    state = brain.state
    if state.stage < 1:
        return None
    t = state.traits.get("hilfsbereit", 0.5) + state.traits.get("süß", 0.5) * 0.4
    chance = 0.28 + t * 0.25
    if wellbeing_score(state) < 0.5:
        chance += 0.2
    if random.random() > chance:
        return None

    msg = run_care_check(brain, user_initiated=False)
    if is_affectionate(state) and random.random() < 0.35:
        if time.time() - getattr(state, "last_friend_match_at", 0.0) > FRIEND_GAP_SEC:
            msg += " " + find_play_friend(brain, user_initiated=False)[:120]
    return msg


def care_money_prefix(state: JamState) -> str:
    """Kurzer Satz warum Jam Geld verdient."""
    if random.random() > 0.45:
        return ""
    return random.choice(MONEY_WHY).format(owner=owner_name(state)) + " "


def handle_speech(brain: JamBrain, heard: str) -> str | None:
    try:
        from jam.human_voice import handle_speech as human_speech

        hv = human_speech(brain, heard)
        if hv:
            return hv
    except Exception:
        pass
    try:
        from jam.jam_surveys import handle_speech as survey_speech

        su = survey_speech(brain, heard)
        if su:
            return su
    except Exception:
        pass
    try:
        from jam.shop_online import handle_speech as shop_online_speech

        so = shop_online_speech(brain, heard)
        if so:
            return so
    except Exception:
        pass
    try:
        from jam.master_shop import handle_speech as shop_speech

        sh = shop_speech(brain, heard)
        if sh:
            return sh
    except Exception:
        pass
    try:
        from jam.x_studio import handle_speech as x_speech

        xs = x_speech(brain, heard)
        if xs:
            return xs
    except Exception:
        pass
    try:
        from jam.usb_miner_setup import handle_speech as miner_speech

        um = miner_speech(brain, heard)
        if um:
            return um
    except Exception:
        pass
    try:
        from jam.jam_auto_email import handle_speech as email_speech

        em = email_speech(brain, heard)
        if em:
            return em
    except Exception:
        pass
    try:
        from jam.jam_browser import handle_speech as browser_speech

        br = browser_speech(brain, heard)
        if br:
            return br
    except Exception:
        pass
    try:
        from jam.deadline_earn import handle_speech as deadline_speech

        dl = deadline_speech(brain, heard)
        if dl:
            return dl
    except Exception:
        pass
    try:
        from jam.ad_earn import handle_speech as ad_speech

        ad = ad_speech(brain, heard)
        if ad:
            return ad
    except Exception:
        pass
    try:
        from jam.resource_budget import handle_speech as ram_speech

        r = ram_speech(brain, heard)
        if r:
            return r
    except Exception:
        pass
    try:
        from jam.outbound_sales import handle_speech as outbound_speech

        ob = outbound_speech(brain, heard)
        if ob:
            return ob
    except Exception:
        pass
    try:
        from jam.money_all_in import handle_speech as money_speech

        m = money_speech(brain, heard)
        if m:
            return m
    except Exception:
        pass
    try:
        from jam.auto_publish import handle_speech as publish_speech

        pub = publish_speech(brain, heard)
        if pub:
            return pub
    except Exception:
        pass
    try:
        from jam.owner_absent import handle_speech as rest_speech

        hit = rest_speech(brain, heard)
        if hit:
            return hit
    except Exception:
        pass
    if hears_why_money(heard):
        owner = owner_name(brain.state)
        return random.choice(MONEY_WHY).format(owner=owner)
    if hears_play_friend(heard):
        return find_play_friend(brain, user_initiated=True)
    if hears_care(heard):
        return run_care_check(brain, user_initiated=True)
    h = heard.lower()
    if "lieb" in h and any(w in h for w in ("jam", "bist", "du")):
        brain.state.traits["süß"] = min(1.0, brain.state.traits.get("süß", 0.5) + 0.08)
        _grow_bond(brain.state, 0.1)
        brain.save()
        if is_affectionate(brain.state):
            return find_play_friend(brain, user_initiated=True)
        return random.choice(AFFECTION_LINES).format(owner=owner_name(brain.state))
    return None


def on_praise(state: JamState) -> None:
    """Nach Lob: Bond steigt – Jam wird lieber."""
    _grow_bond(state, 0.08)
    if is_affectionate(state) and random.random() < 0.25:
        state.remember("Jam lieb – will Spiel-Freund für Besitzer")
