"""``ilum values`` command — view and export live Helm values."""

from __future__ import annotations

from io import StringIO
from pathlib import Path
from typing import Any

import typer

from ilum.cli.defaults import resolve_profile_defaults
from ilum.config.manager import ConfigManager
from ilum.config.paths import IlumPaths
from ilum.core.helm import HelmClient
from ilum.core.kubernetes import KubeClient
from ilum.core.modules import ModuleResolver
from ilum.core.release import ReleaseManager
from ilum.errors import IlumError
from ilum.wizard.deps import ensure_tools


def _walk_dot_path(data: dict[str, Any], path: str) -> Any:
    """Walk a dot-separated path into a nested dict, raising on miss."""
    parts = path.split(".")
    current: Any = data
    for part in parts:
        if not isinstance(current, dict) or part not in current:
            raise typer.BadParameter(f"Key path '{path}' not found in values.")
        current = current[part]
    return current


def values(
    release: str | None = typer.Option(
        None, "--release", "-r", show_default="from profile", help="Helm release name."
    ),
    namespace: str | None = typer.Option(
        None, "--namespace", "-n", show_default="from profile", help="Kubernetes namespace."
    ),
    context: str | None = typer.Option(
        None, "--context", show_default="from profile", help="Kubernetes context."
    ),
    path: str | None = typer.Option(None, "--path", help="Dot-notation path to filter values."),
    all_values: bool = typer.Option(
        False, "--all", "-a", help="Include chart defaults (computed values)."
    ),
    diff: bool = typer.Option(
        False, "--diff", help="Show diff between user-supplied and computed values."
    ),
    revision: int | None = typer.Option(None, "--revision", help="Values at specific revision."),
    export: Path | None = typer.Option(  # noqa: B008
        None, "--export", "-e", help="Export values to a YAML file."
    ),
) -> None:
    """View or export live values from an Ilum release."""
    release, namespace, context = resolve_profile_defaults(release, namespace, context)
    import ilum.cli.output as output_mod

    console = output_mod.console
    from ilum.cli.formatters import CommandResult, OutputFormat, ResultFormatter

    fmt = OutputFormat(console.output_format)

    try:
        ensure_tools(["helm"], console)
        paths = IlumPaths.default()
        paths.ensure_dirs()
        mgr = ReleaseManager(
            helm=HelmClient(kubecontext=context, namespace=namespace),
            k8s=KubeClient(kubecontext=context),
            resolver=ModuleResolver(),
            config_mgr=ConfigManager(paths),
            paths=paths,
        )

        # Verify release exists
        mgr.get_release_info(release)

        # Fetch values
        if revision is not None:
            result = mgr.helm.get_values_at_revision(release, revision)
            data: dict[str, Any] = dict(result.json_data or {})
        elif all_values:
            data = mgr.fetch_computed_values(release)
        else:
            data = mgr.fetch_live_values(release)

        # Apply dot-path filter
        if path:
            data = _walk_dot_path(data, path)

        # Diff mode
        if diff:
            from ilum.core.safety import compute_diff

            user_vals = mgr.fetch_live_values(release)
            all_vals = mgr.fetch_computed_values(release)
            d = compute_diff(user_vals, all_vals)

            if fmt != OutputFormat.TABLE:
                diff_data = {
                    "added": d.added,
                    "changed": {k: {"old": v[0], "new": v[1]} for k, v in d.changed.items()},
                    "removed": d.removed,
                }
                cmd_result = CommandResult(data=diff_data, summary="Values diff")
                ResultFormatter().format(
                    cmd_result,
                    fmt,
                    console,
                    no_headers=console.no_headers,
                    field_selector=console.field_selector,
                )
            else:
                if d.is_empty:
                    console.info("No differences between user-supplied and computed values.")
                else:
                    console.diff_table(d, title="User-Supplied vs Computed Values")
            return

        # Export mode
        if export:
            from ruamel.yaml import YAML

            yaml = YAML()
            yaml.default_flow_style = False
            export.parent.mkdir(parents=True, exist_ok=True)
            yaml.dump(data if isinstance(data, dict) else {"value": data}, export)
            console.success(f"Values exported to {export}")
            return

        # Machine-readable output
        if fmt != OutputFormat.TABLE:
            cmd_result = CommandResult(
                data=data if isinstance(data, (dict, list)) else {"value": data},
                summary="Values",
            )
            ResultFormatter().format(
                cmd_result,
                fmt,
                console,
                no_headers=console.no_headers,
                field_selector=console.field_selector,
            )
            return

        # Table output — render as YAML in a panel
        from ruamel.yaml import YAML

        yaml = YAML()
        yaml.default_flow_style = False
        buf = StringIO()
        yaml.dump(data if isinstance(data, dict) else {"value": data}, buf)
        title = f"Values (revision {revision})" if revision is not None else "Values"
        if all_values:
            title += " (all)"
        console.panel(buf.getvalue(), title=title)

    except IlumError as exc:
        console.handle_error(exc)
        raise typer.Exit(code=1) from exc
