"""Configuration file loader for EarthCatalog.

Supports YAML configuration files with CLI override capability.
The config file allows users to set defaults for all ProcessingConfig options.
"""

from pathlib import Path
from typing import Any

import yaml


def load_config(config_path: Path | str | None = None) -> dict[str, Any]:
    """Load configuration from YAML file.

    Search order:
    1. Explicit path if provided
    2. ./earthcatalog.yaml in current directory
    3. Empty dict (use defaults)

    Args:
        config_path: Optional explicit path to config file.

    Returns:
        Dictionary with configuration values.

    Raises:
        FileNotFoundError: If explicit config_path is provided but doesn't exist.
        yaml.YAMLError: If config file is invalid YAML.
    """
    if config_path is not None:
        path = Path(config_path)
        if not path.exists():
            raise FileNotFoundError(f"Config file not found: {config_path}")
        return _load_yaml_file(path)

    # Check for default config file in current directory
    default_path = Path("earthcatalog.yaml")
    if default_path.exists():
        return _load_yaml_file(default_path)

    # No config file found, return empty dict
    return {}


def _load_yaml_file(path: Path) -> dict[str, Any]:
    """Load and parse a YAML file.

    Args:
        path: Path to YAML file.

    Returns:
        Parsed YAML content as dictionary.
    """
    with open(path) as f:
        content = yaml.safe_load(f)
        # Handle empty files
        if content is None:
            return {}
        if not isinstance(content, dict):
            raise ValueError(f"Config file must contain a YAML mapping, got: {type(content).__name__}")
        return content


def merge_cli_overrides(config: dict[str, Any], cli_args: dict[str, Any]) -> dict[str, Any]:
    """Merge CLI arguments over config file values.

    CLI args with None values are ignored (use config/default).
    This allows CLI to override config file values while preserving
    unspecified defaults.

    Args:
        config: Base configuration from file.
        cli_args: CLI arguments (may contain None values).

    Returns:
        Merged configuration dictionary.
    """
    result = config.copy()

    for key, value in cli_args.items():
        if value is not None:
            result[key] = value

    return result


def save_config(config: dict[str, Any], path: Path | str) -> None:
    """Save configuration to YAML file.

    Args:
        config: Configuration dictionary to save.
        path: Path to write YAML file.
    """
    path = Path(path)
    with open(path, "w") as f:
        yaml.safe_dump(config, f, default_flow_style=False, sort_keys=False)
