"""Bootstrap and manage the local worker runtime used by the macOS app."""

from __future__ import annotations

import json
import os
import shutil
import subprocess
import sys
from dataclasses import dataclass
from datetime import UTC, datetime
from importlib.metadata import PackageNotFoundError, version
from pathlib import Path

_RUNTIME_BUILD_REQUIREMENTS = ("setuptools", "wheel", "jaraco.functools")
_SANITIZED_PYTHON_ENV_VARS = (
    "PYTHONHOME",
    "PYTHONPATH",
    "PYTHONEXECUTABLE",
    "PYTHONSTARTUP",
    "__PYVENV_LAUNCHER__",
    "VIRTUAL_ENV",
)


def _repo_root() -> Path:
    return Path(__file__).resolve().parents[3]


def _resources_root() -> Path:
    override = os.environ.get("HIVE_APP_RESOURCES_DIR", "").strip()
    if override:
        return Path(override).expanduser().resolve()

    resolved = Path(__file__).resolve()
    parts = resolved.parts
    if "Contents" in parts and "Resources" in parts:
        resources_index = parts.index("Resources")
        return Path(*parts[: resources_index + 1])
    return _repo_root()


def _support_root() -> Path:
    override = os.environ.get("HIVE_APP_SUPPORT_DIR", "").strip()
    if override:
        return Path(override).expanduser().resolve()
    return Path("~/Library/Application Support/Ambient").expanduser()


def _source_root(resources_root: Path) -> Path:
    override = os.environ.get("HIVE_APP_PROJECT_DIR", "").strip()
    if override:
        return Path(override).expanduser().resolve()

    bundled = resources_root / "bootstrap" / "project"
    if bundled.exists():
        return bundled
    return _repo_root()


def _uv_bin(resources_root: Path) -> Path:
    override = os.environ.get("HIVE_APP_UV_BIN", "").strip()
    if override:
        return Path(override).expanduser().resolve()

    bundled = resources_root / "bootstrap" / "bin" / "uv"
    if bundled.exists():
        return bundled

    found = shutil.which("uv")
    if not found:
        raise RuntimeError("HiveCompute could not find a usable uv binary for worker setup.")
    return Path(found).resolve()


def _app_version() -> str:
    try:
        return version("hive-compute")
    except PackageNotFoundError:
        return "0"


def _preferred_runtime_python() -> Path | None:
    override = os.environ.get("HIVE_APP_RUNTIME_PYTHON", "").strip()
    if override:
        candidate = Path(override).expanduser().resolve()
        return candidate if candidate.exists() else None

    version_suffix = f"{sys.version_info.major}.{sys.version_info.minor}"
    candidates = [
        Path(f"/opt/homebrew/bin/python{version_suffix}"),
        Path(f"/usr/local/bin/python{version_suffix}"),
    ]
    resolved = shutil.which(f"python{version_suffix}")
    if resolved:
        candidates.append(Path(resolved).resolve())

    for candidate in candidates:
        if candidate.exists():
            return candidate
    return None


@dataclass(frozen=True)
class RuntimeEnvironment:
    support_root: Path
    source_root: Path
    uv_bin: Path
    venv_dir: Path
    venv_python: Path
    venv_hive: Path
    log_dir: Path
    state_file: Path

    def cli_command(self, *args: str) -> list[str]:
        if self.venv_hive.exists():
            return [str(self.venv_hive), *args]
        return [str(self.venv_python), "-m", "hive_compute.cli", *args]


def resolve_runtime_environment() -> RuntimeEnvironment:
    resources_root = _resources_root()
    support_root = _support_root()
    venv_dir = support_root / "runtime" / "venv"
    return RuntimeEnvironment(
        support_root=support_root,
        source_root=_source_root(resources_root),
        uv_bin=_uv_bin(resources_root),
        venv_dir=venv_dir,
        venv_python=venv_dir / "bin" / "python",
        venv_hive=venv_dir / "bin" / "ambient",
        log_dir=Path("~/.ambient/logs").expanduser(),
        state_file=support_root / "runtime" / "runtime-state.json",
    )


def ensure_worker_runtime(runtime: RuntimeEnvironment | None = None) -> RuntimeEnvironment:
    runtime = runtime or resolve_runtime_environment()
    runtime.support_root.mkdir(parents=True, exist_ok=True)
    runtime.log_dir.mkdir(parents=True, exist_ok=True)
    runtime.state_file.parent.mkdir(parents=True, exist_ok=True)

    current_version = _app_version()
    runtime_manifest = _load_runtime_manifest(runtime.source_root)
    runtime_fingerprint = runtime_manifest.get("fingerprint", "")
    runtime_build_id = runtime_manifest.get("build_id", "")
    if _runtime_is_current(runtime, current_version, runtime_fingerprint=runtime_fingerprint):
        return runtime

    if not runtime.source_root.exists():
        raise RuntimeError(f"HiveCompute worker source was not found at {runtime.source_root}.")
    if not runtime.uv_bin.exists():
        raise RuntimeError(f"HiveCompute could not find uv at {runtime.uv_bin}.")

    python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
    preferred_python = _preferred_runtime_python()
    venv_command = [str(runtime.uv_bin), "venv", "--clear", "--python"]
    if preferred_python is not None:
        venv_command.extend([str(preferred_python), str(runtime.venv_dir)])
    else:
        venv_command.extend([python_version, "--managed-python", str(runtime.venv_dir)])
    _run_checked(venv_command, purpose="create the local HiveCompute worker runtime")
    _run_checked(
        [
            str(runtime.uv_bin),
            "pip",
            "install",
            "--python",
            str(runtime.venv_dir),
            *_RUNTIME_BUILD_REQUIREMENTS,
        ],
        purpose="install the local HiveCompute worker build tools",
    )
    _run_checked(
        [
            str(runtime.uv_bin),
            "pip",
            "install",
            "--python",
            str(runtime.venv_dir),
            "--no-build-isolation",
            f"{runtime.source_root}[worker]",
        ],
        purpose="install the local HiveCompute worker runtime",
    )
    _run_checked(
        runtime.cli_command("--help"),
        purpose="validate the local HiveCompute worker runtime entrypoint",
    )
    runtime.state_file.write_text(
        json.dumps(
            {
                "app_version": current_version,
                "python_version": python_version,
                "runtime_python": str(preferred_python) if preferred_python is not None else "uv-managed",
                "runtime_fingerprint": runtime_fingerprint,
                "runtime_build_id": runtime_build_id,
                "updated_at": datetime.now(UTC).isoformat(),
            },
            indent=2,
        )
        + "\n",
        encoding="utf-8",
    )
    return runtime


def _runtime_is_current(
    runtime: RuntimeEnvironment,
    current_version: str,
    *,
    runtime_fingerprint: str,
) -> bool:
    if not runtime.venv_python.exists() or not runtime.venv_hive.exists() or not runtime.state_file.exists():
        return False
    try:
        payload = json.loads(runtime.state_file.read_text(encoding="utf-8"))
    except (OSError, ValueError, TypeError):
        return False
    if payload.get("app_version") != current_version:
        return False
    if runtime_fingerprint:
        return payload.get("runtime_fingerprint") == runtime_fingerprint
    return True


def _load_runtime_manifest(source_root: Path) -> dict[str, str]:
    manifest_path = source_root / ".hive-runtime.json"
    if not manifest_path.exists():
        return {}

    try:
        payload = json.loads(manifest_path.read_text(encoding="utf-8"))
    except (OSError, ValueError, TypeError):
        return {}

    if not isinstance(payload, dict):
        return {}
    return {str(key): str(value) for key, value in payload.items() if value is not None}


def sanitized_runtime_env() -> dict[str, str]:
    env = os.environ.copy()
    for key in _SANITIZED_PYTHON_ENV_VARS:
        env.pop(key, None)
    env.setdefault("PYTHONUTF8", "1")
    return env


def _run_checked(command: list[str], *, purpose: str) -> None:
    try:
        subprocess.run(
            command,
            check=True,
            capture_output=True,
            text=True,
            encoding="utf-8",
            errors="replace",
            env=sanitized_runtime_env(),
        )
    except subprocess.CalledProcessError as exc:
        stderr = (exc.stderr or "").strip()
        stdout = (exc.stdout or "").strip()
        detail = stderr or stdout or f"exit {exc.returncode}"
        raise RuntimeError(f"HiveCompute could not {purpose}: {detail}") from exc
    except OSError as exc:
        raise RuntimeError(f"HiveCompute could not {purpose}: {exc}") from exc
