"""Plugin type definitions for the plugin architecture framework.

Defines the core value objects used across the plugin subsystem:

- :class:`PluginState` — lifecycle state enum for plugins.
- :class:`ExtensionPoint` — metadata describing a pluggable extension.
- :class:`PluginDescriptor` — immutable descriptor for a discovered plugin.

Based on ``docs/specification.md`` Extension Points Summary and
issue #585.
"""

from __future__ import annotations

from enum import StrEnum
from typing import Any

from pydantic import BaseModel, ConfigDict, Field

# ---------------------------------------------------------------------------
# PluginState — lifecycle states
# ---------------------------------------------------------------------------


class PluginState(StrEnum):
    """Lifecycle state of a plugin.

    State transitions::

        DISCOVERED ──► ACTIVATED ──► EXECUTING ──► ACTIVATED
             │              │                          │
             │              └──► DEACTIVATED            └──► ERRORED
             │                                               │
             └──► ERRORED                                    └──► DEACTIVATED
    """

    DISCOVERED = "discovered"
    ACTIVATED = "activated"
    EXECUTING = "executing"
    DEACTIVATED = "deactivated"
    ERRORED = "errored"


# ---------------------------------------------------------------------------
# ExtensionPoint — describes a pluggable extension slot
# ---------------------------------------------------------------------------


class ExtensionPoint(BaseModel):
    """Metadata describing a pluggable extension slot.

    Each extension point is a named slot that accepts implementations
    satisfying a specific Protocol type.

    Attributes:
        name: Unique name identifying this extension point.
        protocol_type: The Protocol type that implementations must satisfy.
        description: Human-readable description of what this slot does.
        registry_key: Key used to look up implementations in a registry.
    """

    name: str = Field(
        ...,
        min_length=1,
        description="Unique extension point name",
    )
    protocol_type: type[Any] = Field(
        ...,
        description="Protocol type that implementations must satisfy",
    )
    description: str = Field(
        default="",
        description="Human-readable description",
    )
    registry_key: str = Field(
        default="",
        description="Registry lookup key for this extension point",
    )

    model_config = ConfigDict(frozen=True, arbitrary_types_allowed=True)


# ---------------------------------------------------------------------------
# PluginDescriptor — immutable metadata for a discovered plugin
# ---------------------------------------------------------------------------


class PluginDescriptor(BaseModel):
    """Immutable descriptor for a discovered plugin.

    Contains all metadata needed to load, validate, and manage a plugin
    through its lifecycle.  Created during discovery and stored in the
    :class:`PluginManager` registry.

    Attributes:
        name: Unique plugin name.
        version: Semantic version string (e.g. ``"1.0.0"``).
        author: Plugin author.
        description: Human-readable description.
        module_path: Python module path for dynamic import.
        class_name: Class name within the module.
        extension_points: Extension points this plugin provides.
        dependencies: Names of plugins this plugin depends on.
        state: Current lifecycle state.
    """

    name: str = Field(
        ...,
        min_length=1,
        description="Unique plugin name",
    )
    version: str = Field(
        default="0.0.0",
        description="Semantic version string",
    )
    author: str = Field(
        default="",
        description="Plugin author",
    )
    description: str = Field(
        default="",
        description="Human-readable description",
    )
    module_path: str = Field(
        default="",
        description="Python module path for dynamic import",
    )
    class_name: str = Field(
        default="",
        description="Class name within the module",
    )
    extension_points: list[str] = Field(
        default_factory=list,
        description="Extension point names this plugin provides",
    )
    dependencies: list[str] = Field(
        default_factory=list,
        description="Names of required plugins",
    )
    state: PluginState = Field(
        default=PluginState.DISCOVERED,
        description="Current lifecycle state",
    )

    model_config = ConfigDict(frozen=False)
