"""Jam lernt selbstständig aus dem Internet – Thema nach Lust und Laune."""

from __future__ import annotations

import random
import re
import time
import webbrowser
from urllib.parse import quote_plus

import requests

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

TIMEOUT = 12
AUTO_GAP_SEC = 50.0
USER_GAP_SEC = 25.0

WIKI_RANDOM = "https://de.wikipedia.org/api/rest_v1/page/random/summary"
WIKI_SEARCH = "https://de.wikipedia.org/w/api.php"
WIKI_SUMMARY = "https://de.wikipedia.org/api/rest_v1/page/summary/{title}"
DDG_API = "https://api.duckduckgo.com/"

# Jam wählt selbst, was ihn gerade interessiert
CURIOSITY_TOPICS: tuple[str, ...] = (
    "Tiere",
    "Weltraum",
    "Dinosaurier",
    "Musik",
    "Computer",
    "Programmieren",
    "Ozean",
    "Wetter",
    "Geschichte",
    "Erfindungen",
    "Sport",
    "Kunst",
    "Pflanzen",
    "Roboter",
    "Mathe",
    "Sprachen",
    "Essen",
    "Spiele",
    "Natur",
    "Energie",
)

SESSION_LINES = (
    "{owner}, ich wollte was über {topic} lernen – aus dem Internet!",
    "Neugier auf {topic}! Ich hol mir Wissen aus dem Netz!",
    "Jam wählt heute: {topic}! Ich lern online!",
    "Boah, {topic} klingt spannend – ich surf und merk mir alles!",
)

RESULT_LINES = (
    "Gelernt ({topic}): {snippet}",
    "Aus dem Internet ({topic}): {snippet}",
    "Neu im Kopf – {topic}: {snippet}",
)


def hears_free_learn(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if any(w in h for w in ("lern", "lerne", "lernen", "lernst")):
        if any(
            w in h
            for w in (
                "willst",
                "will",
                "möchte",
                "moechte",
                "lust",
                "neugier",
                "alles",
                "frei",
                "selbst",
                "internet",
                "netz",
                "online",
                "was du",
            )
        ):
            return True
    if "internet" in h and any(w in h for w in ("lern", "wissen", "merk", "lesen")):
        return True
    return False


def pick_wanted_topic(state: JamState) -> str:
    wants = list(getattr(state, "learn_wants", None) or [])
    words = [
        w
        for w in (getattr(state, "learned_words", None) or [])
        if len(w) >= 5 and w.isalpha()
    ]
    pool = list(CURIOSITY_TOPICS) + wants[-8:] + random.sample(words, min(4, len(words)))
    if not pool:
        return random.choice(CURIOSITY_TOPICS)
    return random.choice(pool)


def _remember_topic_interest(state: JamState, topic: str) -> None:
    wants = list(getattr(state, "learn_wants", None) or [])
    t = topic.strip()[:40]
    if t and t not in wants:
        wants.append(t)
    state.learn_wants = wants[-24:]


def _fetch_wiki_random() -> tuple[str, list[str], str]:
    try:
        r = requests.get(WIKI_RANDOM, timeout=TIMEOUT)
        r.raise_for_status()
        data = r.json()
        title = (data.get("title") or "").strip()
        extract = (data.get("extract") or "").strip()
        url = (data.get("content_urls", {}) or {}).get("desktop", {}).get("page", "")
        if not url and title:
            url = f"https://de.wikipedia.org/wiki/{quote_plus(title.replace(' ', '_'))}"
        from jam.sentence_learn import split_sentences

        sentences = split_sentences(extract, max_count=6)
        if title and len(sentences) < 2:
            sentences.insert(0, f"{title} ist ein spannendes Thema.")
        return title or "Wikipedia", sentences, url
    except (requests.RequestException, KeyError, ValueError, TypeError):
        return "", [], ""


def _fetch_wiki_topic(topic: str) -> tuple[str, list[str], str]:
    try:
        r = requests.get(
            WIKI_SEARCH,
            params={
                "action": "opensearch",
                "search": topic,
                "limit": 1,
                "namespace": 0,
                "format": "json",
            },
            timeout=TIMEOUT,
        )
        r.raise_for_status()
        data = r.json()
        if len(data) < 2 or not data[1]:
            return "", [], ""
        title = data[1][0]
        r2 = requests.get(
            WIKI_SUMMARY.format(title=quote_plus(title.replace(" ", "_"))),
            timeout=TIMEOUT,
        )
        r2.raise_for_status()
        page = r2.json()
        extract = (page.get("extract") or "").strip()
        url = (page.get("content_urls", {}) or {}).get("desktop", {}).get("page", "")
        from jam.sentence_learn import split_sentences

        sentences = split_sentences(extract, max_count=6)
        return title, sentences, url
    except (requests.RequestException, KeyError, ValueError, TypeError):
        return "", [], ""


def _fetch_duckduckgo(topic: str) -> tuple[str, list[str], str]:
    try:
        r = requests.get(
            DDG_API,
            params={"q": topic, "format": "json", "no_html": 1, "skip_disambig": 1},
            timeout=TIMEOUT,
        )
        r.raise_for_status()
        data = r.json()
        abstract = (data.get("AbstractText") or "").strip()
        heading = (data.get("Heading") or topic).strip()
        url = (data.get("AbstractURL") or "").strip()
        if not abstract:
            related = data.get("RelatedTopics") or []
            for item in related[:5]:
                if isinstance(item, dict) and item.get("Text"):
                    abstract = item["Text"]
                    url = item.get("FirstURL", url)
                    break
        from jam.sentence_learn import split_sentences

        sentences = split_sentences(abstract, max_count=4)
        if heading and not sentences:
            sentences = [f"{heading} – interessant!"]
        return heading or topic, sentences, url
    except (requests.RequestException, KeyError, ValueError, TypeError):
        return "", [], ""


def fetch_from_internet(topic: str | None = None) -> tuple[str, list[str], str]:
    """
    Holt Wissen aus dem Netz (Wikipedia + DuckDuckGo).
    Returns (label, sentences, url).
    """
    if topic:
        title, sents, url = _fetch_wiki_topic(topic)
        if sents:
            return title or topic, sents, url
        head, sents, url = _fetch_duckduckgo(topic)
        if sents:
            return head, sents, url
    title, sents, url = _fetch_wiki_random()
    if sents:
        return title, sents, url
    return _fetch_duckduckgo(topic or random.choice(CURIOSITY_TOPICS))


def can_learn_session(state: JamState, *, user: bool = False) -> tuple[bool, str]:
    gap = USER_GAP_SEC if user else AUTO_GAP_SEC
    last = max(
        getattr(state, "last_curiosity_learn", 0.0) or 0.0,
        getattr(state, "last_sentence_learn", 0.0) or 0.0,
    )
    if time.time() - last < gap:
        wait = int(gap - (time.time() - last))
        return False, f"Gleich lern ich wieder – noch {wait} Sekunden!"
    return True, ""


def learn_session(
    brain: JamBrain,
    *,
    user_initiated: bool = False,
    topic: str | None = None,
    open_browser: bool | None = None,
) -> str:
    """Jam lernt online, was er möchte – Sätze, Wörter, Erinnerung."""
    from jam import sentence_learn, web_learn

    state = brain.state
    owner = owner_name(state)
    ok, wait = can_learn_session(state, user=user_initiated)
    if not ok and not user_initiated:
        return wait
    if not ok:
        return wait

    topic = (topic or pick_wanted_topic(state)).strip()[:50]
    _remember_topic_interest(state, topic)

    label, sentences, url = fetch_from_internet(topic)
    if not sentences:
        label, sentences, url = _fetch_wiki_random()

    n = 0
    if sentences:
        n = sentence_learn.remember_sentences(state, sentences)
        snippet = sentences[0]
        for w in re.findall(r"[A-Za-zÄÖÜäöüß]{5,}", " ".join(sentences[:2]))[:6]:
            state.learn_word(w.lower())
        state.remember(f"Internet ({topic}): {snippet[:120]}")
    else:
        snippet = f"Ich sammle Wissen über {topic}."

    state.learn_word("internet")
    state.learn_word(topic.lower()[:20])
    state.last_curiosity_learn = time.time()
    state.last_sentence_learn = time.time()
    state.internet_learn_count = getattr(state, "internet_learn_count", 0) + 1
    state.last_action = "internet_learn"
    state.happiness = min(1.0, state.happiness + 0.1)
    brain.add_xp(6 + n)
    brain.save()

    if open_browser is None:
        open_browser = user_initiated or random.random() < 0.55
    browser_line = ""
    if open_browser:
        try:
            if url:
                webbrowser.open(url, new=2)
            else:
                web_learn.learn_and_open(brain, user_initiated=user_initiated)
            browser_line = " Seite ist offen!"
        except OSError:
            browser_line = ""

    intro = random.choice(SESSION_LINES).format(owner=owner, topic=topic)
    if n:
        fact = random.choice(RESULT_LINES).format(
            topic=label or topic,
            snippet=snippet[:130],
        )
        return f"{intro} {fact}{browser_line}"
    return f"{intro} Ich merk mir: {snippet[:100]}{browser_line}"


def maybe_auto_learn(brain: JamBrain) -> str | None:
    """Von Jam selbst – neugierig = öfter Internet."""
    state = brain.state
    if state.stage < 1:
        return None
    t = state.traits.get("neugierig", 0.5)
    chance = 0.42 + t * 0.35
    if random.random() > chance:
        return None
    ok, _ = can_learn_session(state, user=False)
    if not ok:
        return None
    return learn_session(brain, user_initiated=False)


def handle_speech(brain: JamBrain, heard: str) -> str | None:
    if not hears_free_learn(heard):
        return None
    h = heard.lower()
    topic = None
    for t in CURIOSITY_TOPICS:
        if t.lower() in h:
            topic = t
            break
    if not topic:
        m = re.search(
            r"(?:über|ueber|zu|von|wegen)\s+([a-zäöüß]{3,20})",
            h,
            re.I,
        )
        if m:
            topic = m.group(1).capitalize()
    return learn_session(brain, user_initiated=True, topic=topic, open_browser=True)


def stats_line(state: JamState) -> str:
    n = len(getattr(state, "learned_sentences", []) or [])
    c = getattr(state, "internet_learn_count", 0)
    wants = ", ".join((getattr(state, "learn_wants", []) or [])[-4:])
    return f"Internet-Lernen: {c}×, {n} Sätze. Will lernen: {wants or 'alles Mögliche'}"
