"""Configuration merging utilities for TaskRunner.

Centralizes the logic for merging CLI args, parsed task namespaces, YAML defaults,
and program defaults into a single, testable function with clear precedence rules.

Precedence (most specific to least):
1. Task-level CLI args (parsed via task.add_cli_args into task_ns)
2. Top-level CLI args (e.g., --duration, --interval, --viz)
3. Task-level YAML defaults (tasks.<task_name>.*)
4. Top-level YAML defaults (defaults.*)
5. Program defaults (dataclass field defaults)

"""

from __future__ import annotations

from typing import Any


def merge_config_sources(
    args: object,
    task_ns: object | None,
    top_defaults: dict[str, Any],
    task_defaults: dict[str, Any],
    program_defaults: dict[str, Any],
) -> dict[str, Any]:
    """Merge configuration sources according to precedence rules.

    Args:
        args: Top-level CLI argparse namespace (program-level flags)
        task_ns: Task-specific CLI argparse namespace (from task.add_cli_args)
        top_defaults: Top-level YAML defaults (yaml_data["defaults"])
        task_defaults: Task-specific YAML defaults (yaml_data["tasks"][task_name])
        program_defaults: Dataclass field defaults (e.g., TaskConfig.duration)

    Returns:
        Merged dict with all config values resolved according to precedence.
    """
    merged = dict(program_defaults)
    # Apply top-level YAML defaults
    merged.update(top_defaults)

    # Apply task-specific YAML defaults (overrides top-level)
    # Special handling for display dict - deep merge to preserve backend settings
    for key, value in task_defaults.items():
        if key == "display" and isinstance(value, dict) and "display" in merged:
            # Deep merge display dict
            merged_display = dict(merged["display"])
            merged_display.update(value)
            merged["display"] = merged_display
        else:
            merged[key] = value  # Apply top-level CLI args (overrides YAML)
    for key in ["duration", "interval", "viz", "max_log_size_task", "max_data_size"]:
        val = getattr(args, key, None)
        if val is not None:
            merged[key] = val

    # Apply task-specific CLI args (highest priority)
    if task_ns is not None:
        for key, val in vars(task_ns).items():
            if val is not None:
                merged[key] = val

    return merged
