from __future__ import annotations

from dataclasses import asdict
from pathlib import Path
from typing import Iterable

from cybervisor.adapters.base import AgentAdapter
from cybervisor.adapters.types import AdapterDescriptor
from cybervisor.adapters.claude import ClaudeAdapter
from cybervisor.adapters.gemini import GeminiAdapter
from cybervisor.adapters.mock import MockAdapter

_REGISTERED_ADAPTERS: tuple[AgentAdapter, ...] = (
    GeminiAdapter(),
    ClaudeAdapter(),
    MockAdapter(),
)


def iter_adapters() -> Iterable[AgentAdapter]:
    return _REGISTERED_ADAPTERS


def adapter_descriptors() -> tuple[AdapterDescriptor, ...]:
    return tuple(adapter.descriptor for adapter in _REGISTERED_ADAPTERS)


def supported_agent_names() -> tuple[str, ...]:
    return tuple(adapter.descriptor.name for adapter in _REGISTERED_ADAPTERS)


def adapter_discovery_metadata() -> tuple[dict[str, object], ...]:
    return tuple(asdict(descriptor) for descriptor in adapter_descriptors())


def validate_adapter(adapter: AgentAdapter) -> None:
    descriptor = adapter.descriptor
    if not descriptor.name.strip():
        raise ValueError("Adapter descriptor name must be non-empty")
    if not descriptor.display_name.strip():
        raise ValueError(f"Adapter '{descriptor.name}' display_name must be non-empty")
    if not Path(descriptor.directory).exists():
        raise ValueError(f"Adapter '{descriptor.name}' directory does not exist: {descriptor.directory}")
    if descriptor.capabilities.supports_hooks and adapter.settings_path() is None:
        raise ValueError(f"Adapter '{descriptor.name}' supports hooks but does not declare a settings path")


def get_adapter(name: str) -> AgentAdapter:
    normalized = name.strip().lower()
    for adapter in _REGISTERED_ADAPTERS:
        if adapter.descriptor.name == normalized:
            validate_adapter(adapter)
            return adapter
    supported = ", ".join(sorted(supported_agent_names()))
    raise ValueError(f"Unsupported agent_tool: {name}. Supported values: {supported}")
