"""Portable control-plane envelopes for an executable plugin runtime."""

from __future__ import annotations

from typing import Literal

from pydantic import AwareDatetime, Field, model_validator

from .common import (
    API_VERSION,
    ApiVersion,
    ContractModel,
    Identifier,
    JsonObject,
    ShortText,
)

RuntimeProtocolVersion = Literal["missioncore.nodedc/plugin-runtime/v0alpha1"]
RUNTIME_PROTOCOL_VERSION: RuntimeProtocolVersion = (
    "missioncore.nodedc/plugin-runtime/v0alpha1"
)


class RuntimePluginDescriptor(ContractModel):
    """Plugin-owned declaration used before the host admits any action."""

    api_version: ApiVersion = API_VERSION
    kind: Literal["RuntimePluginDescriptor"] = "RuntimePluginDescriptor"
    runtime_protocol_version: RuntimeProtocolVersion = RUNTIME_PROTOCOL_VERSION
    plugin_id: Identifier
    plugin_version: ShortText
    supported_host_api_versions: tuple[Identifier, ...] = Field(min_length=1)
    action_ids: tuple[Identifier, ...] = Field(min_length=1)

    @model_validator(mode="after")
    def declarations_are_unique(self) -> RuntimePluginDescriptor:
        if len(self.supported_host_api_versions) != len(
            set(self.supported_host_api_versions)
        ):
            raise ValueError("supported host API versions must be unique")
        if len(self.action_ids) != len(set(self.action_ids)):
            raise ValueError("runtime action ids must be unique")
        return self


class RuntimeHandshakeRequest(ContractModel):
    """Host compatibility challenge sent before a runtime becomes ready."""

    api_version: ApiVersion = API_VERSION
    kind: Literal["RuntimeHandshakeRequest"] = "RuntimeHandshakeRequest"
    runtime_protocol_version: RuntimeProtocolVersion = RUNTIME_PROTOCOL_VERSION
    handshake_id: Identifier
    plugin_id: Identifier
    plugin_version: ShortText
    host_api_version: Identifier
    requested_at: AwareDatetime
    required_action_ids: tuple[Identifier, ...] = Field(min_length=1)

    @model_validator(mode="after")
    def required_actions_are_unique(self) -> RuntimeHandshakeRequest:
        if len(self.required_action_ids) != len(set(self.required_action_ids)):
            raise ValueError("required runtime action ids must be unique")
        return self


class RuntimeHandshakeResult(ContractModel):
    """Runtime response proving identity, protocol and admitted host API."""

    api_version: ApiVersion = API_VERSION
    kind: Literal["RuntimeHandshakeResult"] = "RuntimeHandshakeResult"
    handshake_id: Identifier
    runtime_instance_id: Identifier
    accepted_host_api_version: Identifier
    descriptor: RuntimePluginDescriptor
    ready_at: AwareDatetime


class RuntimeHealthSnapshot(ContractModel):
    """Small transport-neutral liveness snapshot for laboratory supervision."""

    api_version: ApiVersion = API_VERSION
    kind: Literal["RuntimeHealthSnapshot"] = "RuntimeHealthSnapshot"
    runtime_instance_id: Identifier
    plugin_id: Identifier
    plugin_version: ShortText
    runtime_protocol_version: RuntimeProtocolVersion = RUNTIME_PROTOCOL_VERSION
    status: Literal["starting", "ready", "stopped"]
    observed_at: AwareDatetime
    detail_code: Identifier | None = None


class RuntimeActionInvocation(ContractModel):
    """Host-admitted invocation delivered to exactly one installed plugin."""

    api_version: ApiVersion = API_VERSION
    kind: Literal["RuntimeActionInvocation"] = "RuntimeActionInvocation"
    invocation_id: Identifier
    plugin_id: Identifier
    action_id: Identifier
    requested_at: AwareDatetime
    parameters: JsonObject = Field(default_factory=dict)


class RuntimeActionResult(ContractModel):
    """Host-validated completion envelope for one runtime invocation."""

    api_version: ApiVersion = API_VERSION
    kind: Literal["RuntimeActionResult"] = "RuntimeActionResult"
    invocation_id: Identifier
    plugin_id: Identifier
    action_id: Identifier
    completed_at: AwareDatetime
    output: JsonObject = Field(default_factory=dict)
