"""TOML configuration parsing and dataclasses."""

from __future__ import annotations

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

if sys.version_info >= (3, 11):
    import tomllib
else:
    try:
        import tomllib  # type: ignore[import-not-found]
    except ModuleNotFoundError:
        import tomli as tomllib  # type: ignore[no-redef]


@dataclass
class ForwardConfig:
    enabled: bool = False
    type: str = "elasticsearch"
    url: str = "http://localhost:9200"
    index: str = "konstant-logs"
    username: str = ""
    password: str = ""
    api_key: str = ""

    @classmethod
    def from_dict(cls, raw: dict[str, Any]) -> ForwardConfig:
        return cls(
            enabled=raw.get("enabled", False),
            type=raw.get("type", "elasticsearch"),
            url=raw.get("url", "http://localhost:9200"),
            index=raw.get("index", "konstant-logs"),
            username=raw.get("username", ""),
            password=raw.get("password", ""),
            api_key=raw.get("api_key", ""),
        )


@dataclass
class LoggingConfig:
    format: str = "text"
    forward: ForwardConfig = field(default_factory=ForwardConfig)

    @classmethod
    def from_dict(cls, raw: dict[str, Any]) -> LoggingConfig:
        forward_raw = raw.get("forward", {})
        return cls(
            format=raw.get("format", "text"),
            forward=ForwardConfig.from_dict(forward_raw),
        )

    def merge(self, override: dict[str, Any]) -> LoggingConfig:
        """Return a new LoggingConfig with fields from *override* layered on top."""
        fmt = override.get("format", self.format)
        fwd_raw = override.get("forward")
        if fwd_raw is not None:
            from dataclasses import asdict
            base = asdict(self.forward)
            base.update(fwd_raw)
            forward = ForwardConfig.from_dict(base)
        else:
            forward = self.forward
        return LoggingConfig(format=fmt, forward=forward)


@dataclass
class ServiceConfig:
    name: str
    script: str
    interpreter: str = "python"
    cwd: str = "."
    env_file: str = ""
    autorestart: bool = True
    max_restarts: int = 10
    restart_delay: int = 5
    args: list[str] = field(default_factory=list)
    logging: LoggingConfig = field(default_factory=LoggingConfig)

    @classmethod
    def from_dict(
        cls,
        name: str,
        raw: dict[str, Any],
        global_logging: LoggingConfig | None = None,
    ) -> ServiceConfig:
        base_logging = global_logging or LoggingConfig()
        svc_logging_raw = raw.get("logging", {})
        logging_cfg = base_logging.merge(svc_logging_raw) if svc_logging_raw else base_logging

        return cls(
            name=name,
            script=raw["script"],
            interpreter=raw.get("interpreter", "python"),
            cwd=raw.get("cwd", "."),
            env_file=raw.get("env_file", ""),
            autorestart=raw.get("autorestart", True),
            max_restarts=raw.get("max_restarts", 10),
            restart_delay=raw.get("restart_delay", 5),
            args=raw.get("args", []),
            logging=logging_cfg,
        )

    @property
    def resolved_cwd(self) -> Path:
        return Path(self.cwd).resolve()

    @property
    def script_path(self) -> Path:
        return self.resolved_cwd / self.script


@dataclass
class KonstantConfig:
    services: dict[str, ServiceConfig]

    @classmethod
    def load(cls, path: Path | None = None) -> KonstantConfig:
        if path is None:
            path = Path.cwd() / "konstant.toml"
        path = path.resolve()
        if not path.exists():
            raise FileNotFoundError(f"Config file not found: {path}")
        with open(path, "rb") as f:
            raw = tomllib.load(f)

        global_logging_raw = raw.get("logging", {})
        global_logging = LoggingConfig.from_dict(global_logging_raw)

        services_raw = raw.get("services", {})
        if not services_raw:
            raise ValueError("No [services.*] sections found in config")
        services = {
            name: ServiceConfig.from_dict(name, cfg, global_logging)
            for name, cfg in services_raw.items()
        }
        return cls(services=services)

    def get_service(self, name: str) -> ServiceConfig:
        if name not in self.services:
            raise KeyError(f"Service '{name}' not found in config")
        return self.services[name]

    def service_names(self) -> list[str]:
        return list(self.services.keys())
