"""Configuration loading for the reference curator pipeline.

Loads YAML configs from ~/.config/reference-curator/ with env var substitution.
Falls back to bundled defaults in shared/config/.
"""

from __future__ import annotations

import os
import re
from pathlib import Path
from typing import Any

import yaml
from dotenv import load_dotenv

# Load user env if present
_env_file = Path.home() / ".reference-curator.env"
if _env_file.is_file():
    load_dotenv(_env_file)

# Config search paths (user override → bundled defaults)
USER_CONFIG_DIR = Path.home() / ".config" / "reference-curator"
BUNDLED_CONFIG_DIR = Path(__file__).resolve().parents[4] / "config"  # shared/config/

# Default storage paths
DEFAULT_LIBRARY_PATH = Path(
    os.environ.get("REFERENCE_LIBRARY_PATH", "~/Documents/reference-library")
).expanduser()
DEFAULT_STATE_DIR = DEFAULT_LIBRARY_PATH / "pipeline_state"


def _expand_env_vars(value: str) -> str:
    """Expand ${VAR:-default} patterns in a string."""
    def _replace(match: re.Match) -> str:
        var_expr = match.group(1)
        if ":-" in var_expr:
            var_name, default = var_expr.split(":-", 1)
            return os.environ.get(var_name, default)
        return os.environ.get(var_expr, match.group(0))

    return re.sub(r"\$\{([^}]+)}", _replace, value)


def _expand_recursive(obj: Any) -> Any:
    """Recursively expand env vars in a parsed YAML structure."""
    if isinstance(obj, str):
        expanded = _expand_env_vars(obj)
        # Expand ~ in path-like strings
        if expanded.startswith("~"):
            expanded = str(Path(expanded).expanduser())
        return expanded
    if isinstance(obj, dict):
        return {k: _expand_recursive(v) for k, v in obj.items()}
    if isinstance(obj, list):
        return [_expand_recursive(item) for item in obj]
    return obj


def load_config(name: str) -> dict:
    """Load a YAML config file by name (without extension).

    Searches user config dir first, then bundled defaults.
    Expands ${VAR:-default} env var patterns in all string values.

    Args:
        name: Config file name without .yaml extension
              (e.g., "db_config", "pipeline_config", "crawl_config", "export_config")

    Returns:
        Parsed and expanded config dict.

    Raises:
        FileNotFoundError: If config file not found in any search path.
    """
    filename = f"{name}.yaml"

    for config_dir in [USER_CONFIG_DIR, BUNDLED_CONFIG_DIR]:
        config_path = config_dir / filename
        if config_path.is_file():
            with open(config_path) as f:
                raw = yaml.safe_load(f) or {}
            return _expand_recursive(raw)

    raise FileNotFoundError(
        f"Config '{filename}' not found in {USER_CONFIG_DIR} or {BUNDLED_CONFIG_DIR}"
    )


def get_db_config() -> dict:
    """Load database configuration."""
    return load_config("db_config")


def get_pipeline_config() -> dict:
    """Load pipeline orchestrator configuration."""
    return load_config("pipeline_config")


def get_crawl_config() -> dict:
    """Load crawler configuration."""
    return load_config("crawl_config")


def get_export_config() -> dict:
    """Load export configuration."""
    return load_config("export_config")


def get_library_path() -> Path:
    """Get the reference library base path."""
    return DEFAULT_LIBRARY_PATH


def get_state_dir() -> Path:
    """Get the pipeline state directory."""
    try:
        cfg = get_pipeline_config()
        state_dir = cfg.get("state", {}).get("state_directory")
        if state_dir:
            return Path(state_dir).expanduser()
    except FileNotFoundError:
        pass
    return DEFAULT_STATE_DIR


def get_state_backend() -> str:
    """Get the state backend type: 'mysql' or 'file'."""
    try:
        cfg = get_pipeline_config()
        return cfg.get("state", {}).get("backend", "file")
    except FileNotFoundError:
        return "file"
