"""Configuration loading: YAML file + environment variables + CLI overrides."""

from __future__ import annotations

import os
from dataclasses import dataclass, field
from datetime import datetime, timezone
from pathlib import Path

import yaml

from xc_dl import __version__


@dataclass
class DownloadConfig:
    convert: str | None = None
    convert_sample_rate: int = 16000
    convert_channels: int = 1
    convert_bit_depth: int = 16
    max_retries: int = 3
    min_free_space_bytes: int = 1_073_741_824  # 1 GiB default


@dataclass
class QueryPreset:
    query: str = ""
    description: str = ""


@dataclass
class Config:
    api_key: str = ""
    data_dir: Path = field(default_factory=lambda: Path("./xc-dataset"))
    concurrency: int = 8
    metadata_concurrency: int = 4
    rate_limit: float = 5.0
    log_level: str = "INFO"
    log_file: Path | None = None
    download: DownloadConfig = field(default_factory=DownloadConfig)
    queries: dict[str, QueryPreset] = field(default_factory=dict)


def load_config(config_path: Path | None = None) -> Config:
    """Load config from YAML file, then overlay environment variables."""
    cfg = Config()

    if config_path and config_path.exists():
        with open(config_path) as f:
            raw = yaml.safe_load(f) or {}

        general = raw.get("general", {})
        if "api_key" in general:
            cfg.api_key = general["api_key"]
        if "data_dir" in general:
            cfg.data_dir = Path(general["data_dir"])
        if "concurrency" in general:
            cfg.concurrency = int(general["concurrency"])
        if "metadata_concurrency" in general:
            cfg.metadata_concurrency = int(general["metadata_concurrency"])
        if "rate_limit" in general:
            cfg.rate_limit = float(general["rate_limit"])
        if "log_level" in general:
            cfg.log_level = general["log_level"]
        if "log_file" in general:
            cfg.log_file = Path(general["log_file"])

        dl = raw.get("download", {})
        if "convert" in dl:
            cfg.download.convert = dl["convert"]
        if "convert_sample_rate" in dl:
            cfg.download.convert_sample_rate = int(dl["convert_sample_rate"])
        if "convert_channels" in dl:
            cfg.download.convert_channels = int(dl["convert_channels"])
        if "max_retries" in dl:
            cfg.download.max_retries = int(dl["max_retries"])
        if "min_free_space" in dl:
            from xc_dl.utils import parse_size
            cfg.download.min_free_space_bytes = parse_size(dl["min_free_space"])

        for name, preset_data in raw.get("queries", {}).items():
            cfg.queries[name] = QueryPreset(
                query=preset_data.get("query", ""),
                description=preset_data.get("description", ""),
            )

    # Environment overrides
    env_key = os.environ.get("XC_API_KEY")
    if env_key:
        cfg.api_key = env_key

    return cfg


def save_query_preset(config_path: Path, name: str, query: str, description: str = "") -> None:
    """Save a named query preset to the config file."""
    raw: dict = {}
    if config_path.exists():
        with open(config_path) as f:
            raw = yaml.safe_load(f) or {}

    raw.setdefault("queries", {})[name] = {
        "query": query,
        "description": description,
    }

    config_path.parent.mkdir(parents=True, exist_ok=True)
    with open(config_path, "w") as f:
        yaml.dump(raw, f, default_flow_style=False, sort_keys=False)


def load_dataset_config(data_dir: Path) -> dict | None:
    """Load download-config.yaml from a dataset directory. Returns None if not found."""
    path = data_dir / "download-config.yaml"
    if not path.exists():
        return None
    with open(path) as f:
        return yaml.safe_load(f)


def save_dataset_config(data_dir: Path, query: str, **params: object) -> None:
    """Write download-config.yaml to the dataset directory (excludes API key)."""
    config: dict[str, object] = {
        "xc_dl_version": __version__,
        "query": query,
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "parameters": {k: v for k, v in params.items() if v is not None},
    }
    path = data_dir / "download-config.yaml"
    data_dir.mkdir(parents=True, exist_ok=True)
    with open(path, "w") as f:
        yaml.dump(config, f, default_flow_style=False, sort_keys=False)
