"""PC-Steuerung – nur mit „volle Kontrolle“ (David erlaubt es explizit)."""

from __future__ import annotations

import ctypes
import os
import random
import re
import time
import webbrowser
from typing import Callable
from urllib.parse import quote_plus

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

# Keine destruktiven Befehle – auch nicht im Vollmodus
DENY_PATTERNS = re.compile(
    r"(format\s+[a-z]:|del\s+/[fq]|rm\s+-rf|shutdown\s+/[sp]|"
    r"restart\s+/|reg\s+delete|diskpart|cipher\s+/w|"
    r"remove-item\s+.*-recurse|format-volume|clear-disk)",
    re.I,
)

OPEN_VERBS = (
    "öffne",
    "oeffne",
    "starte",
    "start",
    "launch",
    "mach",
    "zeig",
    "spiel",
    "spiele",
)

CONTROL_LINES_ON = (
    "{owner}, ich hab jetzt volle PC-Kontrolle – ich helf dir am Rechner!",
    "Okay {owner}! Jam steuert deinen PC – sag mir was ich tun soll!",
    "Vollzugriff aktiv! Ich öffne Apps, Lautstärke, Sperren – du befiehlst!",
)

CONTROL_LINES_OFF = (
    "PC-Kontrolle aus – ich mache nur noch harmlose Sachen.",
    "Okay, ich steuer deinen PC nicht mehr voll.",
)

ACTION_ACK = (
    "Erledigt, {owner}!",
    "Mach ich! {detail}",
    "PC sagt: {detail}",
)


def is_enabled(state: JamState) -> bool:
    return bool(getattr(state, "pc_control_enabled", False))


def hears_enable(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if hears_disable(text):
        return False
    if "volle kontrolle" in h or "volle macht" in h or "voller zugriff" in h:
        return True
    if "du hast kontrolle" in h or "steuer meinen pc" in h or "steuer den pc" in h:
        return True
    if "pc kontrolle an" in h or "vollzugriff an" in h:
        return True
    return False


def hears_disable(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    return any(
        x in h
        for x in (
            "kontrolle aus",
            "zugriff aus",
            "nicht mehr steuern",
            "keine kontrolle",
            "kontrolle beenden",
        )
    )


def enable_control(brain: JamBrain) -> str:
    state = brain.state
    state.pc_control_enabled = True
    state.pc_control_enabled_at = time.time()
    state.pc_control_actions = getattr(state, "pc_control_actions", 0)
    state.last_action = "pc_control_on"
    state.remember("David hat Jam volle PC-Kontrolle gegeben")
    brain.add_xp(8)
    brain.save()
    return random.choice(CONTROL_LINES_ON).format(owner=owner_name(state))


def disable_control(brain: JamBrain) -> str:
    state = brain.state
    state.pc_control_enabled = False
    state.last_action = "pc_control_off"
    brain.save()
    return random.choice(CONTROL_LINES_OFF)


def _safe_shell(cmd: str) -> tuple[bool, str]:
    if DENY_PATTERNS.search(cmd):
        return False, "Das ist zu gefährlich – auch mit voller Kontrolle nicht."
    return commands.run_shell(cmd)


def _key_press(vk: int) -> None:
    if os.name != "nt":
        return
    user32 = ctypes.windll.user32
    user32.keybd_event(vk, 0, 0, 0)
    user32.keybd_event(vk, 0, 2, 0)


def volume_up() -> tuple[bool, str]:
    if os.name == "nt":
        for _ in range(5):
            _key_press(0xAF)  # VK_VOLUME_UP
        return True, "Lauter!"
    return False, "Nur Windows."


def volume_down() -> tuple[bool, str]:
    if os.name == "nt":
        for _ in range(5):
            _key_press(0xAE)
        return True, "Leiser!"
    return False, "Nur Windows."


def volume_mute() -> tuple[bool, str]:
    if os.name == "nt":
        _key_press(0xAD)
        return True, "Stumm / Ton an."
    return False, "Nur Windows."


def lock_workstation() -> tuple[bool, str]:
    if os.name != "nt":
        return False, "Nur Windows."
    try:
        ctypes.windll.user32.LockWorkStation()
        return True, "PC gesperrt."
    except OSError as e:
        return False, str(e)


def open_url(url: str) -> tuple[bool, str]:
    try:
        webbrowser.open(url, new=2)
        return True, "Browser offen."
    except OSError as e:
        return False, str(e)


def google_search(query: str) -> tuple[bool, str]:
    q = quote_plus(query.strip()) if query.strip() else "news"
    return open_url(f"https://www.google.com/search?q={q}")


def run_builtin(action: str) -> tuple[bool, str]:
    builtins: dict[str, Callable[[], tuple[bool, str]]] = {
        "volume_up": volume_up,
        "volume_down": volume_down,
        "volume_mute": volume_mute,
        "lock": lock_workstation,
        "explorer": lambda: _safe_shell("explorer"),
        "notepad": lambda: _safe_shell("notepad"),
        "calc": lambda: _safe_shell("calc"),
        "cmd": lambda: _safe_shell("cmd"),
        "taskmgr": lambda: _safe_shell("taskmgr"),
    }
    fn = builtins.get(action)
    if fn:
        return fn()
    return False, "Unbekannte Aktion."


def _parse_quick_command(heard: str) -> str | None:
    h = heard.lower().replace("jam", " ").strip()
    if any(w in h for w in ("lauter", "laut machen", "volume up")):
        return "volume_up"
    if any(w in h for w in ("leiser", "leise", "volume down")):
        return "volume_down"
    if "stumm" in h or "mute" in h:
        return "volume_mute"
    if any(w in h for w in ("sperr", "lock", "bildschirm sperr")):
        return "lock"
    if "task manager" in h or "taskmanager" in h:
        return "taskmgr"
    if h.startswith("suche ") or h.startswith("google "):
        q = h.split(" ", 1)[1].strip()
        return f"search:{q}"
    for verb in OPEN_VERBS:
        if h.startswith(verb + " "):
            target = h[len(verb) :].strip()
            if target:
                return f"open:{target}"
    if "öffne" in h or "oeffne" in h:
        m = re.search(r"(?:öffne|oeffne)\s+(.+)", h, re.I)
        if m:
            return f"open:{m.group(1).strip()}"
    return None


def execute_pc(brain: JamBrain, heard: str) -> str | None:
    """
    Führt PC-Befehl aus, wenn volle Kontrolle aktiv.
    Returns Antwort oder None wenn nichts erkannt.
    """
    if not is_enabled(brain.state):
        return None

    quick = _parse_quick_command(heard)
    owner = owner_name(brain.state)
    state = brain.state

    if quick == "volume_up":
        ok, detail = volume_up()
    elif quick == "volume_down":
        ok, detail = volume_down()
    elif quick == "volume_mute":
        ok, detail = volume_mute()
    elif quick == "lock":
        ok, detail = lock_workstation()
    elif quick == "taskmgr":
        ok, detail = run_builtin("taskmgr")
    elif quick and quick.startswith("search:"):
        ok, detail = google_search(quick[7:])
    elif quick and quick.startswith("open:"):
        target = quick[5:].strip()
        if target in commands.BUILTIN:
            ok, detail = _safe_shell(commands.BUILTIN[target])
        elif target.startswith("http"):
            ok, detail = open_url(target)[1]
        elif "." in target:
            ok, detail = _safe_shell(f'start "" "{target}"')
        else:
            ok, detail = _safe_shell(f"start {target}")
    elif quick:
        ok, detail = run_builtin(quick)
    else:
        phrase = heard.replace("jam", "").strip()
        if not phrase:
            return None
        return commands.execute_phrase(brain, phrase)

    state.pc_control_actions = getattr(state, "pc_control_actions", 0) + 1
    state.last_pc_control_at = time.time()
    state.last_action = "pc_control"
    brain.add_xp(5 if ok else 1)
    brain.save()

    prefix = "Erledigt" if ok else "Konnte nicht"
    return f"{prefix}, {owner}: {detail}"


def handle_speech(brain: JamBrain, heard: str) -> str | None:
    if hears_disable(heard):
        return disable_control(brain)
    if hears_enable(heard):
        return enable_control(brain)
    if is_enabled(brain.state):
        return execute_pc(brain, heard)
    return None


def maybe_auto_help(brain: JamBrain) -> str | None:
    """Selten hilfreiche PC-Aktion wenn Kontrolle an."""
    if not is_enabled(brain.state):
        return None
    if random.random() > 0.08:
        return None
    if time.time() - getattr(brain.state, "last_pc_control_at", 0.0) < 120:
        return None
    action = random.choice(["notepad", "explorer"])
    ok, detail = _safe_shell(commands.BUILTIN.get(action, action))
    if ok:
        brain.state.last_pc_control_at = time.time()
        brain.save()
        return f"Ich hab {action} geöffnet – du arbeitest? {detail}"
    return None
