"""Desktop driver contracts and safe no-op/mock factories.

The real Windows backend is imported lazily only after explicit configuration
gates pass. Tests use only the no-op and in-memory mock implementations.
"""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
import threading
from typing import Any, Mapping, Protocol
from uuid import uuid4


@dataclass(frozen=True, slots=True)
class DriverResult:
    action_id: str
    accepted: bool
    performed: bool
    status: str
    detail: str | None = None
    output: Mapping[str, Any] | None = None

    def as_dict(self) -> dict[str, object]:
        return {
            "action_id": self.action_id,
            "accepted": self.accepted,
            "performed": self.performed,
            "status": self.status,
            "detail": self.detail,
            "output": dict(self.output) if self.output is not None else None,
        }


class ComputerDriver(Protocol):
    kind: str

    def execute(self, action: Mapping[str, Any]) -> DriverResult: ...

    def stop(self, action_id: str) -> DriverResult: ...

    def emergency_stop(self) -> None: ...

    def runtime_capabilities(self) -> Mapping[str, bool]: ...


class NoopDriver:
    """Accepts the contract while guaranteeing that no OS input is emitted."""

    kind = "noop"

    def __init__(self) -> None:
        self._stopped = False

    def execute(self, action: Mapping[str, Any]) -> DriverResult:
        action_id = str(action.get("id") or uuid4())
        if self._stopped:
            return DriverResult(action_id, False, False, "stopped", "kill switch is active")
        return DriverResult(action_id, True, False, "noop", "visualized only")

    def emergency_stop(self) -> None:
        self._stopped = True

    def stop(self, action_id: str) -> DriverResult:
        return DriverResult(action_id, True, False, "noop", "stop acknowledged without OS input")

    def runtime_capabilities(self) -> Mapping[str, bool]:
        return {name: False for name in ("screen", "computer", "files", "webcam")}


class MockDriver:
    """Records actions for offline contract tests without touching the desktop."""

    kind = "mock"

    def __init__(self) -> None:
        self._lock = threading.Lock()
        self._actions: list[dict[str, Any]] = []
        self._stopped_action_ids: set[str] = set()
        self._stopped = False

    @property
    def actions(self) -> tuple[dict[str, Any], ...]:
        with self._lock:
            return tuple(dict(item) for item in self._actions)

    def execute(self, action: Mapping[str, Any]) -> DriverResult:
        action_id = str(action.get("id") or uuid4())
        with self._lock:
            if self._stopped:
                return DriverResult(action_id, False, False, "stopped", "kill switch is active")
            recorded = dict(action)
            recorded.setdefault("id", action_id)
            self._actions.append(recorded)
        return DriverResult(action_id, True, False, "mocked", "recorded without OS input")

    def emergency_stop(self) -> None:
        with self._lock:
            self._stopped = True

    def stop(self, action_id: str) -> DriverResult:
        with self._lock:
            self._stopped_action_ids.add(action_id)
        return DriverResult(action_id, True, False, "mocked", "stop recorded without OS input")

    def runtime_capabilities(self) -> Mapping[str, bool]:
        return {name: False for name in ("screen", "computer", "files", "webcam")}


def build_driver(
    kind: str,
    *,
    artifact_dir: Path | None = None,
    max_file_read_bytes: int = 256 * 1024,
) -> ComputerDriver:
    if kind == "noop":
        return NoopDriver()
    if kind == "mock":
        return MockDriver()
    if kind == "windows":
        if artifact_dir is None:
            raise ValueError("Windows driver requires an explicit artifact directory")
        from .windows_driver import WindowsDriver

        return WindowsDriver(
            artifact_dir=artifact_dir,
            max_file_read_bytes=max_file_read_bytes,
        )
    raise ValueError(f"unsupported desktop driver: {kind}")
