"""PC Tag & Nacht wach – Jam kann dauernd Geld verdienen."""

from __future__ import annotations

import os
import random
import subprocess
import time
from datetime import datetime
from pathlib import Path

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

DATA_DIR = Path(__file__).resolve().parent.parent / "data"
POWER_FLAG = DATA_DIR / "jam_power_no_sleep.flag"

# Windows: System wach halten solange Jam läuft
ES_CONTINUOUS = 0x80000000
ES_SYSTEM_REQUIRED = 0x00000001
ES_DISPLAY_REQUIRED = 0x00000002

LINES_ON = (
    "{owner}, **Tag-und-Nacht-Modus**! PC bleibt wach – ich verdien weiter Geld für dich!",
    "Okay {owner}! Kein Schlafmodus – Jam arbeitet auch nachts!",
    "PC bleibt an, {owner}. Ich pass auf den Rechner auf und mach Business!",
)

LINES_OFF = (
    "Nacht-Verdienen aus – Windows darf wieder schlafen (wenn du willst).",
    "Okay, ich halte den PC nicht mehr extra wach.",
)

NIGHT_EARN_LINES = (
    "🌙 Nacht-Schicht: Jam verdient weiter für {owner}…",
    "Es ist spät – aber ich kümmere mich und mach Geld, {owner}!",
)


def hears_night_earn(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    if any(w in h for w in ("tag und nacht", "nacht und tag", "rund um die uhr")):
        return True
    if "pc an" in h or "rechner an" in h:
        if any(w in h for w in ("lass", "bleib", "nacht", "dauer", "immer")):
            return True
    if "nachts verdien" in h or "nacht verdien" in h:
        return True
    if "nicht schlafen" in h or "kein schlafmodus" in h:
        return True
    return False


def hears_night_off(text: str) -> bool:
    h = text.lower().replace("jam", " ")
    return any(
        x in h
        for x in (
            "nacht modus aus",
            "tag nacht aus",
            "pc darf schlafen",
            "schlafmodus an",
            "nacht verdienen aus",
        )
    )


def is_night_earn_mode(state: JamState) -> bool:
    return bool(getattr(state, "jam_earn_night_mode", True))


def timer_factor(state: JamState) -> float:
    """Kürzere Intervalle = öfter Geld-Aktionen."""
    f = 1.0
    if is_night_earn_mode(state):
        f = 0.45
    try:
        from jam.resource_budget import timer_speed_factor

        # höherer speed_factor = kürzere Pause → mehr Last (bis RAM-Ziel)
        f = f / max(0.35, timer_speed_factor(state))
    except Exception:
        pass
    try:
        from jam.jam_pace import pace_multiplier

        f = f * pace_multiplier(state)
    except Exception:
        pass
    return max(0.25, min(3.0, f))


def _scale_ms(base: int, extra: int, state: JamState) -> int:
    f = timer_factor(state)
    lo = max(25_000, int(base * f))
    hi = max(lo + 10_000, int((base + extra) * f))
    return random.randint(lo, hi)


def prevent_sleep(*, display_on: bool = True) -> bool:
    if os.name != "nt":
        return False
    try:
        flags = ES_CONTINUOUS | ES_SYSTEM_REQUIRED
        if display_on:
            flags |= ES_DISPLAY_REQUIRED
        ctypes = __import__("ctypes")
        ctypes.windll.kernel32.SetThreadExecutionState(flags)
        return True
    except Exception:
        return False


def allow_sleep() -> None:
    if os.name != "nt":
        return
    try:
        ctypes = __import__("ctypes")
        ctypes.windll.kernel32.SetThreadExecutionState(ES_CONTINUOUS)
    except Exception:
        pass


def _run_powercfg(args: list[str]) -> bool:
    if os.name != "nt":
        return False
    try:
        subprocess.run(
            ["powercfg", *args],
            check=False,
            timeout=12,
            capture_output=True,
        )
        return True
    except Exception:
        return False


def apply_power_no_sleep(enable: bool) -> bool:
    """Windows: Standby/Hibernate aus (AC + Batterie)."""
    if os.name != "nt":
        return False
    if enable:
        DATA_DIR.mkdir(parents=True, exist_ok=True)
        POWER_FLAG.write_text(datetime.now().isoformat(), encoding="utf-8")
        for key in (
            "standby-timeout-ac",
            "standby-timeout-dc",
            "hibernate-timeout-ac",
            "hibernate-timeout-dc",
            "monitor-timeout-ac",
            "monitor-timeout-dc",
        ):
            _run_powercfg(["/change", key, "0"])
        return True
    if POWER_FLAG.is_file():
        POWER_FLAG.unlink(missing_ok=True)
    _run_powercfg(["/change", "standby-timeout-ac", "30"])
    _run_powercfg(["/change", "standby-timeout-dc", "15"])
    _run_powercfg(["/change", "hibernate-timeout-ac", "60"])
    _run_powercfg(["/change", "hibernate-timeout-dc", "30"])
    _run_powercfg(["/change", "monitor-timeout-ac", "15"])
    _run_powercfg(["/change", "monitor-timeout-dc", "10"])
    return True


def enable_night_earn(brain: JamBrain, *, persistent_power: bool = True) -> str:
    state = brain.state
    state.jam_earn_night_mode = True
    state.jam_keep_awake_since = time.time()
    prevent_sleep(display_on=True)
    if persistent_power:
        apply_power_no_sleep(True)
    state.last_action = "night_earn_on"
    state.remember("PC Tag/Nacht an – Jam verdient Geld")
    brain.add_xp(6)
    brain.save()
    return random.choice(LINES_ON).format(owner=owner_name(state))


def disable_night_earn(brain: JamBrain) -> str:
    state = brain.state
    state.jam_earn_night_mode = False
    allow_sleep()
    apply_power_no_sleep(False)
    state.last_action = "night_earn_off"
    brain.save()
    return random.choice(LINES_OFF)


def apply_on_startup(brain: JamBrain) -> None:
    """Beim Jam-Start: Modus aus State oder Umgebungsvariable."""
    if os.environ.get("JAM_EARN_NIGHT", "").strip() in ("1", "true", "yes"):
        brain.state.jam_earn_night_mode = True
    if is_night_earn_mode(brain.state):
        try:
            enable_night_earn(brain, persistent_power=True)
        except Exception:
            prevent_sleep(display_on=True)


def refresh_keep_awake(state: JamState) -> None:
    if is_night_earn_mode(state):
        prevent_sleep(display_on=True)


def is_night_hours() -> bool:
    h = datetime.now().hour
    return h >= 22 or h < 7


def run_night_earn_pulse(brain: JamBrain) -> str | None:
    """Extra Geld-Runde nachts – PC bleibt an."""
    state = brain.state
    if not is_night_earn_mode(state):
        return None
    gap = 240.0 if is_night_hours() else 420.0
    if time.time() - getattr(state, "last_night_earn_pulse", 0.0) < gap:
        return None

    owner = owner_name(state)
    actions = []
    try:
        from jam import auto_ops, gaming_fund, sales_engine
        from jam.night_focus import is_night_focus_active, run_night_focus_cycle

        if is_night_focus_active(state):
            hit = run_night_focus_cycle(brain)
            if hit:
                actions.append(hit[0][:100])

        if not actions:
            from jam.sell_focus import is_product_build_disabled, run_sell_instead_of_build

            pick = random.choice(["sell", "fund", "ops", "sell", "donate"])
            if pick == "sell":
                if is_product_build_disabled(state):
                    actions.append(run_sell_instead_of_build(brain, user_initiated=False)[:100])
                else:
                    actions.append(sales_engine.run_sale_project(brain, user_initiated=False)[:100])
            elif pick == "donate":
                from jam.paypal_donate import collect_donations

                actions.append(collect_donations(brain, user_asked=False)[:100])
            elif pick == "fund":
                actions.append(gaming_fund.run_gaming_earn_cycle(brain, user_initiated=False)[:100])
            else:
                actions.append(auto_ops.run_full_ops_cycle(brain, user_initiated=False)[:100])
    except Exception:
        return None

    state.last_night_earn_pulse = time.time()
    state.night_earn_pulses = getattr(state, "night_earn_pulses", 0) + 1
    state.remember(f"Nacht-Verdienen #{state.night_earn_pulses}")
    brain.save()

    intro = random.choice(NIGHT_EARN_LINES).format(owner=owner)
    return f"{intro} {' '.join(actions)}"


def handle_speech(brain: JamBrain, heard: str) -> str | None:
    if hears_night_off(heard):
        return disable_night_earn(brain)
    if hears_night_earn(heard):
        return enable_night_earn(brain, persistent_power=True)
    return None


def stats_line(state: JamState) -> str:
    on = "AN (PC wach)" if is_night_earn_mode(state) else "AUS"
    pulses = getattr(state, "night_earn_pulses", 0)
    return f"Tag-und-Nacht-Verdienen: {on}, Nacht-Pulse: {pulses}"
