"""
Author: Vasiliy Zdanovskiy
email: vasilyvz@gmail.com

Orchestration config section for SimpleConfig (TZ section 10).

Parses orchestration key from raw config and builds OrchestrationSectionConfig
with static_servers as list of StaticServerEntry. Used by simple_config.load().
"""

from __future__ import annotations

import logging
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional

from mcp_proxy_adapter.core.orchestration.orchestration_config import (
    StaticServerEntry,
    validate_static_servers,
)

logger = logging.getLogger(__name__)


@dataclass
class OrchestrationSectionConfig:
    """
    Orchestration configuration section (TZ section 10).

    Attributes:
        discovery_enabled: Whether discovery is enabled.
        polling_interval: Polling interval in seconds.
        initial_poll_timeout: Timeout for initial poll in seconds.
        stale_snapshot_behavior: Policy for stale snapshot.
        mutex_lock_timeout: Mutex lock timeout in seconds.
        static_servers: Optional list of static server entries (host, port, id UUID4).
    """

    discovery_enabled: bool = False
    polling_interval: float = 30.0
    initial_poll_timeout: float = 60.0
    stale_snapshot_behavior: str = "keep"
    mutex_lock_timeout: float = 5.0
    static_servers: List[StaticServerEntry] = field(default_factory=list)


def parse_orchestration_section(data: Dict[str, Any]) -> OrchestrationSectionConfig:
    """
    Parse orchestration section from raw config dict.

    Missing key is treated as default (discovery_enabled=False, empty static_servers).
    Each static_servers entry must have host, port, id (validated later by
    validate_static_servers at load time).

    Args:
        data: Raw dict from config (e.g. content.get("orchestration", {})).

    Returns:
        OrchestrationSectionConfig with parsed values.
    """
    if not data:
        return OrchestrationSectionConfig()

    static_raw = data.get("static_servers") or []
    static_servers: List[StaticServerEntry] = []
    for item in static_raw:
        if isinstance(item, dict):
            host = item.get("host", "")
            port = int(item.get("port", 0)) if item.get("port") is not None else 0
            sid = (item.get("id") or "").strip() if item.get("id") is not None else ""
            static_servers.append(
                StaticServerEntry(host=host, port=port, id=sid)  # noqa: A001
            )

    return OrchestrationSectionConfig(
        discovery_enabled=bool(data.get("discovery_enabled", False)),
        polling_interval=float(data.get("polling_interval", 30.0)),
        initial_poll_timeout=float(data.get("initial_poll_timeout", 60.0)),
        stale_snapshot_behavior=str(data.get("stale_snapshot_behavior", "keep")),
        mutex_lock_timeout=float(data.get("mutex_lock_timeout", 5.0)),
        static_servers=static_servers,
    )


def load_orchestration_section(
    data: Optional[Dict[str, Any]],
) -> OrchestrationSectionConfig:
    """
    Parse and validate orchestration section; fail-fast on invalid UUID4.

    If data is None or empty, returns default config. If static_servers
    is non-empty, validates each entry id as UUID4; on any error logs
    and raises ValueError so startup is terminated.

    Args:
        data: Raw orchestration dict (e.g. content.get("orchestration")).

    Returns:
        OrchestrationSectionConfig.

    Raises:
        ValueError: When static_servers has missing or invalid UUID4.
    """
    section = parse_orchestration_section(data or {})
    if not section.static_servers:
        return section
    errors = validate_static_servers(section.static_servers)
    if errors:
        for err in errors:
            logger.error(
                "Orchestration static_servers validation: %s",
                err.message,
            )
        raise ValueError(
            "Orchestration static_servers validation failed: "
            "missing or invalid UUID4 for at least one entry. "
            "Startup terminated (fail-fast)."
        )
    return section
