"""Provider-neutral Codegen execution placement.

This module is deliberately small: Core resolves an admitted execution target and
the existing lifecycle continues to own submit/callback/finalize behavior.  It is
not a scheduler and it never accepts runner labels or hostnames from a customer.
"""
from __future__ import annotations

from dataclasses import dataclass
from enum import StrEnum
from typing import Any


class CodegenExecutionProvider(StrEnum):
    GITHUB = "github"
    SELF_HOSTED = "self_hosted"
    LOCAL_DEV = "local_dev"


class CodegenExecutionError(ValueError):
    """A configured execution target is invalid or unsafe."""


@dataclass(frozen=True)
class CodegenExecutionTarget:
    provider: CodegenExecutionProvider
    target: str
    runner_class: str
    config_version: str = "1"

    def snapshot(self) -> dict[str, str]:
        return {
            "provider": self.provider.value,
            "target": self.target,
            "runner_class": self.runner_class,
            "execution_config_version": self.config_version,
        }


# These are administrative identifiers, not arbitrary GitHub ``runs-on`` values.
# Adding a target is an operator change in Core and can later map to an admitted
# label/pool without changing Codegen business logic.
ADMITTED_TARGETS: dict[CodegenExecutionProvider, frozenset[str]] = {
    CodegenExecutionProvider.GITHUB: frozenset({"hosted"}),
    CodegenExecutionProvider.SELF_HOSTED: frozenset({"codegen-pool-a", "server1"}),
    CodegenExecutionProvider.LOCAL_DEV: frozenset({"development"}),
}


def resolve_codegen_execution(settings: Any) -> CodegenExecutionTarget:
    """Resolve the one canonical platform placement from trusted settings.

    ``codegen_execution_backend`` is retained only as a compatibility bridge for
    older deployments.  The legacy ``server`` value maps to local development and
    is rejected in production; it is never a fallback from an external failure.
    """
    provider_raw = str(getattr(settings, "codegen_execution_provider", "github")).lower().strip()
    target = str(getattr(settings, "codegen_execution_target", "hosted")).lower().strip()
    legacy = str(getattr(settings, "codegen_execution_backend", "github_actions")).lower().strip()
    if provider_raw == "github_actions":
        provider_raw = "github"
    if legacy == "server" and provider_raw == "github" and target == "hosted":
        provider_raw, target = "local_dev", "development"
    try:
        provider = CodegenExecutionProvider(provider_raw)
    except ValueError as exc:
        raise CodegenExecutionError(f"Unsupported Codegen execution provider: {provider_raw!r}") from exc
    if target not in ADMITTED_TARGETS[provider]:
        raise CodegenExecutionError(f"Execution target {target!r} is not admitted for {provider.value}")
    environment_value = getattr(settings, "environment", "dev")
    environment = str(getattr(environment_value, "value", environment_value)).lower()
    if provider is CodegenExecutionProvider.LOCAL_DEV:
        if environment == "prod" or not bool(getattr(settings, "codegen_allow_local_dev", False)):
            raise CodegenExecutionError("Local Core Codegen execution is disabled; use an external runner")
    runner_class = str(getattr(settings, "codegen_execution_runner_class", "linux_standard"))
    return CodegenExecutionTarget(
        provider=provider,
        target=target,
        runner_class=runner_class,
        config_version=str(getattr(settings, "codegen_execution_config_version", "1")),
    )
