from __future__ import annotations

from copy import deepcopy
from typing import Any


class RuntimeErrorForUser(RuntimeError):
    pass


class DesktopPetRuntime:
    def __init__(self) -> None:
        self.state: dict[str, Any] = {
            "packageId": None,
            "mode": None,
            "activeAction": "sit",
            "running": False,
            "paused": False,
            "hidden": False,
            "scale": 1.0,
            "position": {"x": 40, "y": 40},
            "reduceMotion": False,
            "alwaysOnTop": True,
            "soundEnabled": False,
        }

    def load_package(
        self,
        package: dict[str, Any],
        *,
        user_approved: bool,
        mode: str,
    ) -> dict[str, Any]:
        if mode not in {"preview", "desktop"}:
            raise RuntimeErrorForUser("runtime mode must be preview or desktop")
        if mode == "desktop" and not user_approved:
            raise RuntimeErrorForUser("user approval is required before desktop loading")
        if not package.get("id"):
            raise RuntimeErrorForUser("approved pet package is missing or deleted")

        self.state.update(
            {
                "packageId": package["id"],
                "mode": mode,
                "activeAction": "sit",
                "running": mode == "desktop",
                "paused": False,
                "hidden": False,
                "soundEnabled": False,
            }
        )
        return deepcopy(self.state)

    def set_action(self, action: str) -> dict[str, Any]:
        self.state["activeAction"] = action
        return deepcopy(self.state)

    def set_position(self, x: int, y: int) -> dict[str, Any]:
        self.state["position"] = {"x": int(x), "y": int(y)}
        return deepcopy(self.state)

    def set_scale(self, scale: float) -> dict[str, Any]:
        value = float(scale)
        if value < 0.5 or value > 2.0:
            raise RuntimeErrorForUser("scale must be between 0.5 and 2.0")
        self.state["scale"] = value
        return deepcopy(self.state)

    def set_reduce_motion(self, enabled: bool) -> dict[str, Any]:
        self.state["reduceMotion"] = bool(enabled)
        return deepcopy(self.state)

    def pause(self) -> dict[str, Any]:
        self.state["paused"] = True
        self.state["running"] = False
        return deepcopy(self.state)

    def resume(self) -> dict[str, Any]:
        if self.state["mode"] == "desktop" and not self.state["hidden"]:
            self.state["paused"] = False
            self.state["running"] = True
        return deepcopy(self.state)

    def hide(self) -> dict[str, Any]:
        self.state["hidden"] = True
        self.state["running"] = False
        return deepcopy(self.state)

    def show(self) -> dict[str, Any]:
        self.state["hidden"] = False
        if self.state["mode"] == "desktop" and not self.state["paused"]:
            self.state["running"] = True
        return deepcopy(self.state)

    def quit(self) -> dict[str, Any]:
        self.state["running"] = False
        self.state["paused"] = False
        self.state["hidden"] = False
        return deepcopy(self.state)
