"""Routing and domain operations selected by a hosting profile.

Domain inventory stays with Core. Adapters bind a hostname they are given.
The default adapter records the profile strategy and refuses live route changes.
"""
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 HostingRoutingAdapter(Protocol):
    provider_id: str

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

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

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

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

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

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

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

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

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

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


class ProfileRoutingAdapter:
    """Describe routing from the profile. Do not move production traffic."""

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

    def _facts(self) -> dict[str, Any]:
        profile = get_hosting_profile(self.provider_id)
        return {
            "ok": True,
            "provider_id": profile.provider_id,
            "routing_strategy": profile.routing_strategy,
            "ssl_lifecycle": profile.ssl_lifecycle,
        }

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

    def provision_preview(self, hostname: str, context: dict[str, Any]) -> dict[str, Any]:
        del hostname, context
        return self._facts()

    def provision_production(self, hostname: str, context: dict[str, Any]) -> dict[str, Any]:
        del hostname, context
        return self._facts()

    def bind_custom_domain(self, hostname: str, context: dict[str, Any]) -> dict[str, Any]:
        del hostname, context
        return self._facts()

    def bind_subdomain(self, hostname: str, context: dict[str, Any]) -> dict[str, Any]:
        del hostname, context
        return self._facts()

    def verify_dns(self, hostname: str, context: dict[str, Any]) -> dict[str, Any]:
        del hostname, context
        return self._facts()

    def ssl_readiness(self, hostname: str, context: dict[str, Any]) -> dict[str, Any]:
        del hostname, context
        return self._facts()

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

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

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


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


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


def get_routing_adapter(provider_id: str) -> HostingRoutingAdapter:
    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 ProfileRoutingAdapter(key)
