"""Values file loading, merging, and manipulation for Helm deployments."""

from __future__ import annotations

import copy
from pathlib import Path
from typing import Any

from ruamel.yaml import YAML
from ruamel.yaml.comments import CommentedMap

from ilum.errors import ValuesError


def deep_merge(base: dict[str, Any], overlay: dict[str, Any]) -> dict[str, Any]:
    if isinstance(base, CommentedMap):
        for key, overlay_val in overlay.items():
            if key in base and isinstance(base[key], dict) and isinstance(overlay_val, dict):
                base[key] = deep_merge(base[key], overlay_val)
            else:
                base[key] = overlay_val
        return base

    result: dict[str, Any] = copy.deepcopy(base)
    for key, overlay_val in overlay.items():
        if key in result and isinstance(result[key], dict) and isinstance(overlay_val, dict):
            result[key] = deep_merge(result[key], overlay_val)
        else:
            result[key] = copy.deepcopy(overlay_val)
    return result


def load_values(path: Path) -> dict[str, Any]:
    if not path.exists():
        raise ValuesError(f"Values file not found: {path}")
    try:
        yaml = YAML()
        yaml.preserve_quotes = True
        data = yaml.load(path)
    except Exception as exc:
        raise ValuesError(f"Failed to parse YAML file {path}: {exc}") from exc
    if data is None:
        return dict(CommentedMap())
    return dict(data)


def save_values(data: dict[str, Any], path: Path) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    yaml = YAML()
    yaml.preserve_quotes = True
    yaml.dump(data, path)


def merge_values_files(base_path: Path, *overlay_paths: Path) -> dict[str, Any]:
    result = load_values(base_path)
    for overlay_path in overlay_paths:
        overlay = load_values(overlay_path)
        result = deep_merge(result, overlay)
    return result


def _coerce_value(raw: str) -> bool | int | float | str:
    if raw.lower() == "true":
        return True
    if raw.lower() == "false":
        return False
    try:
        return int(raw)
    except ValueError:
        pass
    try:
        return float(raw)
    except ValueError:
        pass
    return raw


def apply_set_flags(data: dict[str, Any], flags: list[str]) -> dict[str, Any]:
    result: dict[str, Any] = copy.deepcopy(data)
    for flag in flags:
        if "=" not in flag:
            raise ValuesError(f"Malformed --set flag: '{flag}' (expected format: key.path=value)")
        key_path, _, raw_value = flag.partition("=")
        parts = key_path.split(".")
        value: Any = _coerce_value(raw_value)

        target: dict[str, Any] = result
        for part in parts[:-1]:
            if part not in target or not isinstance(target[part], dict):
                target[part] = {}
            target = target[part]
        target[parts[-1]] = value
    return result
