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

Orchestration configuration dataclasses and validation.

Defines OrchestrationConfig and StaticServerEntry per TZ section 10.
Validates static server list: each entry must have id present and valid UUID4.
On validation failure, returns a list of ValidationError; caller must log
each error and terminate startup immediately (fail-fast).
No network calls; only config validation.
"""

from __future__ import annotations

import logging
import uuid
from dataclasses import dataclass, field
from typing import List, Optional, Union

from mcp_proxy_adapter.core.errors import ValidationError

logger = logging.getLogger(__name__)


@dataclass
class StaticServerEntry:
    """
    Single static server candidate from configuration.

    Attributes:
        host: Server host (e.g. hostname or IP).
        port: Server port.
        id: Server identifier; must be a valid UUID4 string.
    """

    host: str
    port: int
    id: str  # noqa: A003


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

    Attributes:
        discovery_enabled: Whether discovery is enabled.
        polling_interval: Polling interval in seconds (float or int).
        initial_poll_timeout: Timeout for initial poll in seconds (float or int).
        stale_snapshot_behavior: Policy for stale snapshot (string or enum-like).
        mutex_lock_timeout: Mutex lock timeout for inter-process operations in seconds (float or int).
        static_servers: Optional list of static server entries; each id must be valid UUID4.
    """

    discovery_enabled: bool
    polling_interval: Union[float, int]
    initial_poll_timeout: Union[float, int]
    stale_snapshot_behavior: str
    mutex_lock_timeout: Union[float, int]
    static_servers: Optional[List[StaticServerEntry]] = field(default_factory=list)


def _is_valid_uuid4(value: str) -> bool:
    """
    Return True if value is a non-empty string and valid UUID4.

    Args:
        value: String to check.

    Returns:
        True if valid UUID4, False otherwise.
    """
    if not value or not isinstance(value, str):
        return False
    value_stripped = value.strip()
    if not value_stripped:
        return False
    try:
        uuid.UUID(value_stripped, version=4)
        return True
    except (ValueError, TypeError, AttributeError):
        return False


def validate_static_servers(
    entries: Optional[List[StaticServerEntry]],
) -> List[ValidationError]:
    """
    Validate that every static server entry has id present and valid UUID4.

    Caller must log each error and terminate startup immediately if the
    returned list is non-empty (fail-fast). No network or proxy access;
    only config validation.

    Args:
        entries: List of static server entries (may be None or empty).

    Returns:
        List of ValidationError; empty if all entries are valid.
        Non-empty list means startup must be aborted.
    """
    errors: List[ValidationError] = []
    if not entries:
        return errors

    for i, entry in enumerate(entries):
        if not hasattr(entry, "id"):
            errors.append(
                ValidationError(
                    f"orchestration.static_servers[{i}]: missing 'id' field"
                )
            )
            continue
        raw_id = getattr(entry, "id", None)
        if raw_id is None:
            errors.append(
                ValidationError(
                    f"orchestration.static_servers[{i}]: id is missing (null)"
                )
            )
            continue
        if not isinstance(raw_id, str):
            errors.append(
                ValidationError(
                    f"orchestration.static_servers[{i}]: id must be a string, got {type(raw_id).__name__}"
                )
            )
            continue
        if not raw_id.strip():
            errors.append(
                ValidationError(f"orchestration.static_servers[{i}]: id is empty")
            )
            continue
        if not _is_valid_uuid4(raw_id):
            errors.append(
                ValidationError(
                    f"orchestration.static_servers[{i}]: id must be valid UUID4, got {raw_id!r}"
                )
            )

    if errors:
        for err in errors:
            logger.error("Orchestration config validation: %s", err.message)

    return errors
