from dataclasses import dataclass, field
from pathlib import Path
from typing import Any

import yaml


@dataclass(frozen=True, slots=True)
class RetentionConfig:
    enabled: bool = False
    job_observations_days: int = 30
    job_runs_days: int = 180
    status_events_days: int = 180
    collector_runs_days: int = 90
    watcher_events_days: int = 90


@dataclass(frozen=True, slots=True)
class CollectorConfig:
    name: str
    type: str
    enabled: bool = True
    timeout_seconds: int = 10
    definitions: tuple[dict[str, Any], ...] = ()


@dataclass(frozen=True, slots=True)
class WatcherConfig:
    cycle_interval_seconds: int = 60
    database_path: Path = Path("./data/watcher.sqlite")
    timezone_display: str = "Europe/Madrid"
    log_level: str = "INFO"
    api_host: str = "127.0.0.1"
    api_port: int = 8088
    remote_ingest_enabled: bool = True
    agent_auth_token_env: str = "HERMES_WATCHER_AGENT_TOKEN"
    remote_stale_after_seconds: int = 120
    max_remote_event_bytes: int = 512 * 1024
    retention: RetentionConfig = field(default_factory=RetentionConfig)


@dataclass(frozen=True, slots=True)
class AppConfig:
    watcher: WatcherConfig
    collectors: tuple[CollectorConfig, ...]


def _positive(value: Any, name: str) -> int:
    result = int(value)
    if result <= 0:
        raise ValueError(f"{name} must be positive")
    return result


def load_config(path: Path) -> AppConfig:
    with path.open("r", encoding="utf-8") as handle:
        raw = yaml.safe_load(handle) or {}
    watcher_raw = raw.get("watcher", {})
    retention_raw = watcher_raw.get("retention", {})
    retention = RetentionConfig(
        enabled=bool(retention_raw.get("enabled", False)),
        job_observations_days=_positive(retention_raw.get("job_observations_days", 30), "retention"),
        job_runs_days=_positive(retention_raw.get("job_runs_days", 180), "retention"),
        status_events_days=_positive(retention_raw.get("status_events_days", 180), "retention"),
        collector_runs_days=_positive(retention_raw.get("collector_runs_days", 90), "retention"),
        watcher_events_days=_positive(retention_raw.get("watcher_events_days", 90), "retention"),
    )
    watcher = WatcherConfig(
        cycle_interval_seconds=_positive(watcher_raw.get("cycle_interval_seconds", 60), "cycle_interval_seconds"),
        database_path=Path(watcher_raw.get("database_path", "./data/watcher.sqlite")),
        timezone_display=str(watcher_raw.get("timezone_display", "Europe/Madrid")),
        log_level=str(watcher_raw.get("log_level", "INFO")),
        api_host=str(watcher_raw.get("api_host", "127.0.0.1")),
        api_port=_positive(watcher_raw.get("api_port", 8088), "api_port"),
        remote_ingest_enabled=bool(raw.get("remote_ingest", {}).get("enabled", True)),
        agent_auth_token_env=str(raw.get("remote_ingest", {}).get("auth_token_env", "HERMES_WATCHER_AGENT_TOKEN")),
        remote_stale_after_seconds=_positive(raw.get("remote_ingest", {}).get("stale_after_seconds", 120), "remote_stale_after_seconds"),
        max_remote_event_bytes=_positive(raw.get("remote_ingest", {}).get("max_event_bytes", 512 * 1024), "max_event_bytes"),
        retention=retention,
    )
    collector_items: list[CollectorConfig] = []
    for item in raw.get("collectors", []):
        collector_items.append(CollectorConfig(
            name=str(item["name"]),
            type=str(item["type"]),
            enabled=bool(item.get("enabled", True)),
            timeout_seconds=_positive(item.get("timeout_seconds", 10), "timeout_seconds"),
            definitions=tuple(item.get("definitions", ())),
        ))
    if not collector_items:
        raise ValueError("at least one collector must be configured")
    return AppConfig(watcher=watcher, collectors=tuple(collector_items))
