"""Profile-selected deployment operations.

Generic orchestration asks the registry for an adapter. Pages and W4P register
their own build facts. Live provider calls stay unbound here so a migration
plan cannot deploy by accident.
"""
from __future__ import annotations

from typing import Any, Protocol

from src.domain.hosting.profile import (
    HostingProfileError,
    canonical_provider_id,
    find_hosting_profile,
    get_hosting_profile,
)

_ADAPTERS: dict[str, Any] = {}


class HostingExecutionAdapter(Protocol):
    provider_id: str

    def plan_build(self, framework: str) -> dict[str, Any]: ...

    def prepare(self, context: dict[str, Any]) -> dict[str, Any]: ...

    def deploy(self, context: dict[str, Any]) -> dict[str, Any]: ...

    def readiness(self, context: dict[str, Any]) -> dict[str, Any]: ...

    def rollback(self, context: dict[str, Any]) -> dict[str, Any]: ...


class ProfileExecutionAdapter:
    """Build plan from the registered profile. Live deploy is refused."""

    def __init__(self, provider_id: str) -> None:
        self.provider_id = canonical_provider_id(provider_id)

    def plan_build(self, framework: str) -> dict[str, Any]:
        profile = get_hosting_profile(self.provider_id)
        command, output = profile.build_outputs.get(framework, ("", ""))
        return {
            "provider_id": profile.provider_id,
            "command": command,
            "output": output,
            "ssr_supported": profile.ssr_supported,
            "server_function_surface": profile.server_function_surface,
            "bff_strategy": profile.bff_strategy,
        }

    def prepare(self, context: dict[str, Any]) -> dict[str, Any]:
        del context
        profile = get_hosting_profile(self.provider_id)
        return {"ok": True, "detail": profile.execution_mode}

    def deploy(self, context: dict[str, Any]) -> dict[str, Any]:
        del context
        raise HostingProfileError(f"live deployment is not bound for {self.provider_id}")

    def readiness(self, context: dict[str, Any]) -> dict[str, Any]:
        del context
        raise HostingProfileError(f"readiness is not bound for {self.provider_id}")

    def rollback(self, context: dict[str, Any]) -> dict[str, Any]:
        del context
        raise HostingProfileError(f"rollback is not bound for {self.provider_id}")


def register_execution_adapter(provider_id: str, adapter: HostingExecutionAdapter) -> None:
    _ADAPTERS[canonical_provider_id(provider_id)] = adapter


def unregister_execution_adapter(provider_id: str) -> None:
    _ADAPTERS.pop(canonical_provider_id(provider_id), None)


def get_execution_adapter(provider_id: str) -> HostingExecutionAdapter:
    key = canonical_provider_id(provider_id)
    found = _ADAPTERS.get(key)
    if found is not None:
        return found
    if find_hosting_profile(key) is None:
        raise HostingProfileError(f"unregistered hosting provider {provider_id}")
    return ProfileExecutionAdapter(key)


def uses_worker_ci(provider_id: str | None) -> bool:
    """True when the profile waits for project CI instead of a Pages deployment poll."""

    profile = find_hosting_profile(provider_id)
    if profile is None:
        return False
    return profile.health_check == "worker_readiness"
