from __future__ import annotations

import logging
from pathlib import Path
from typing import Any

import gin

from src.conf.pipeline_conf import PipelineConfig
from src.conf.hardware_conf import HardwareConfig
from src.conf.models_conf import ModelsConfig
from src.conf.input_conf import InputConfig
from src.conf.seg_conf import SegConfig

logger = logging.getLogger(__name__)


def base_gin_files(cfg_dir: Path) -> list[Path]:
    """Return base .gin files, excluding dataset-specific pipeline variants.

    Files named ``pipeline_<dataset>.gin`` (e.g. ``pipeline_uav_visloc.gin``)
    are per-dataset overrides loaded selectively by their own run scripts —
    they must NOT be globbed into the default World-UAV config, or their
    ``PipelineConfig.*`` bindings would override ``pipeline.gin``.
    """
    return sorted(
        f for f in cfg_dir.glob("*.gin")
        if not f.name.startswith("pipeline_")
    )


def load_all_configs(path2cfg: str) -> dict[str, Any]:
    """Parse ALL .gin files at once and return all config objects.

    Clears gin global state first, then loads all .gin files in sorted
    order, then creates config instances from the fully-populated state.

    Args:
        path2cfg: Path to config directory (WITH trailing slash).

    Returns:
        Dictionary with config objects keyed by short name.

    Raises:
        FileNotFoundError: If path2cfg does not exist or has no .gin files.
    """
    cfg_dir = Path(path2cfg)
    if not cfg_dir.is_dir():
        raise FileNotFoundError(f"Config directory not found: {cfg_dir}")

    gin_files = base_gin_files(cfg_dir)
    if not gin_files:
        raise FileNotFoundError(f"No .gin files in {cfg_dir}")

    gin.clear_config()
    gin.parse_config_files_and_bindings(
        config_files=[str(f) for f in gin_files],
        bindings=[],
    )
    logger.info("Loaded %d gin files from %s", len(gin_files), cfg_dir)

    configs = {
        "pipeline": PipelineConfig(),
        "hardware": HardwareConfig(),
        "models": ModelsConfig(),
        "input": InputConfig(),
        "seg": SegConfig(),
    }
    logger.info("Created config objects: %s", list(configs.keys()))
    return configs
