"""Shared first-run setup helpers for the macOS app."""

from __future__ import annotations

import platform
from pathlib import Path
from typing import Any

import httpx
import yaml

from hive_compute.model_ids import DEFAULT_SUPPORTED_TRANSCRIPTION_MODELS
from hive_compute.worker.idle_detector import get_hardware_info
from hive_compute.worker.keychain import store_worker_token

CONFIG_PATH = Path("~/.ambient/config.yaml").expanduser()


class AppSetupError(RuntimeError):
    """A user-facing failure during first-run app setup."""

    def __init__(self, message: str, *, code: str = "setup_failed"):
        super().__init__(message)
        self.code = code


def enroll_worker_install(
    coordinator_url: str,
    enrollment_token: str | None = None,
    *,
    worker_id: str | None = None,
) -> dict[str, Any]:
    """Register a worker and write the local config."""
    token = (enrollment_token or "").strip()
    headers = {"X-Enrollment-Token": token} if token else {}

    resolved_worker_id = worker_id or platform.node()
    hardware = get_hardware_info()
    try:
        response = httpx.post(
            f"{coordinator_url.rstrip('/')}/api/v1/workers/register",
            headers=headers,
            json={
                "worker_id": resolved_worker_id,
                "chip": hardware.get("chip"),
                "memory_gb": hardware.get("memory_gb"),
                "available_handlers": ["transcribe"],
                "available_models": list(DEFAULT_SUPPORTED_TRANSCRIPTION_MODELS),
            },
            timeout=15,
        )
        response.raise_for_status()
    except httpx.HTTPStatusError as exc:
        status_code = exc.response.status_code
        if status_code in {401, 403}:
            if token:
                raise AppSetupError(
                    "That invitation code is invalid or expired. Ask for a fresh code and try again.",
                    code="invalid_invitation",
                ) from exc
            raise AppSetupError(
                "This Ambient deployment still requires an invitation code before this Mac can join. "
                "Ask for a code and try again.",
                code="invitation_required",
            ) from exc
        if status_code >= 500:
            raise AppSetupError(
                "Ambient could not reach the coordinator right now. Wait a moment and try again.",
                code="coordinator_unavailable",
            ) from exc
        raise AppSetupError(
            f"Ambient setup failed with HTTP {status_code}. Try again in a moment.",
            code="http_error",
        ) from exc
    except httpx.TimeoutException as exc:
        raise AppSetupError(
            "Ambient could not reach the coordinator. Check your internet connection and try again.",
            code="network_error",
        ) from exc
    except httpx.HTTPError as exc:
        raise AppSetupError(
            "Ambient could not reach the coordinator. Check your internet connection and try again.",
            code="network_error",
        ) from exc

    data = response.json()
    worker_token = data.get("worker_token")
    if not worker_token:
        raise AppSetupError("Coordinator response was incomplete. Try again or contact support.", code="bad_response")

    try:
        worker_token_keychain = store_worker_token(worker_token, coordinator_url, resolved_worker_id)
    except Exception as exc:
        raise AppSetupError(
            "Ambient could not store its worker credential in macOS Keychain. "
            "Unlock Keychain Access and try again.",
            code="keychain_error",
        ) from exc

    config = {
        "coordinator_url": coordinator_url,
        "worker_id": resolved_worker_id,
        "worker_token_keychain": worker_token_keychain,
        "handlers": {
            "transcribe": {
                "backend": "mlx-whisper",
                "model": "large-v3",
                "quantization": "4bit",
                "language": "en",
                "prewarm_model_on_startup": True,
                "supported_models": list(DEFAULT_SUPPORTED_TRANSCRIPTION_MODELS),
            }
        },
        "idle_detection": {"min_idle_minutes": 5, "require_ac_power": True, "check_thermal": True},
        "polling": {"interval_seconds": 30, "busy_interval_seconds": 5, "idle_interval_seconds": 60},
    }
    try:
        write_worker_config(config)
    except Exception as exc:
        raise AppSetupError(
            "Ambient could not write its local config file. Check folder permissions and try again.",
            code="config_write_error",
        ) from exc
    return config


def write_worker_config(config: dict[str, Any], config_path: Path | None = None) -> Path:
    """Persist the worker config with owner-only permissions."""
    config_path = config_path or CONFIG_PATH
    config_path.parent.mkdir(parents=True, exist_ok=True)
    if not config_path.exists():
        config_path.write_text("", encoding="utf-8")
    config_path.chmod(0o600)
    config_path.write_text(yaml.safe_dump(config, default_flow_style=False), encoding="utf-8")
    return config_path
