"""CLI commands for config — list, set, get, unset."""

from __future__ import annotations

import json

import click

from kuberoku.cli.context import resolve_app
from kuberoku.cli.output import info, success

_MASK = "********"


@click.group("config", invoke_without_command=True)
@click.option("--app", "-a", "app_flag", default=None, help="Target app.")
@click.option("--shell", "shell_fmt", is_flag=True, help="Output as KEY=VALUE lines.")
@click.option("--json", "json_fmt", is_flag=True, help="Output as JSON.")
@click.option("--reveal", is_flag=True, help="Unmask secret values.")
@click.pass_context
def config(
    ctx: click.Context,
    app_flag: str | None,
    shell_fmt: bool,
    json_fmt: bool,
    reveal: bool,
) -> None:
    """Show or manage config vars."""
    if ctx.invoked_subcommand is not None:
        # Store app_flag for subcommands
        ctx.ensure_object(dict)
        ctx.obj["_config_app"] = app_flag
        return

    app_name = resolve_app(app_flag)
    factory = ctx.obj["factory"]
    sources = factory.config.list_with_sources(app_name)

    if not sources:
        info("No config vars set.")
        return

    has_secrets = any(src == "secret" for _, src in sources.values())
    if reveal and has_secrets:
        click.echo("WARNING: Revealing secret values.", err=True)

    if json_fmt:
        data = {
            k: (v if reveal or src == "configmap" else _MASK)
            for k, (v, src) in sorted(sources.items())
        }
        click.echo(json.dumps(data, indent=2, sort_keys=True))
        return

    if shell_fmt:
        for key in sorted(sources):
            value, source = sources[key]
            display = value if reveal or source == "configmap" else _MASK
            click.echo(f"{key}={display}")
        return

    # Default: table-like output
    max_key = max(len(k) for k in sources)
    for key in sorted(sources):
        value, source = sources[key]
        display = value if reveal or source == "configmap" else _MASK
        click.echo(f"{key.ljust(max_key)}  {display}")


@config.command("set")
@click.argument("pairs", nargs=-1, required=True)
@click.option("--app", "-a", "app_flag", default=None, help="Target app.")
@click.option("--secret", "is_secret", is_flag=True, help="Store in Secret.")
@click.option("--no-restart", "no_restart", is_flag=True, help="Skip rolling restart.")
@click.pass_context
def set_cmd(
    ctx: click.Context,
    pairs: tuple[str, ...],
    app_flag: str | None,
    is_secret: bool,
    no_restart: bool,
) -> None:
    """Set config vars (KEY=VALUE ...)."""
    # Resolve app from subcommand flag, parent flag, or resolution chain
    parent_app = ctx.obj.get("_config_app")
    app_name = resolve_app(app_flag or parent_app)
    factory = ctx.obj["factory"]

    vars_dict: dict[str, str] = {}
    for pair in pairs:
        if "=" not in pair:
            raise click.BadParameter(
                f"Invalid format: '{pair}'. Expected KEY=VALUE.",
                param_hint="'PAIRS'",
            )
        key, value = pair.split("=", 1)
        vars_dict[key] = value

    result = factory.config.set(
        app_name,
        vars_dict,
        secret=is_secret,
        no_restart=no_restart,
        on_step=lambda msg: info(msg),
    )
    for key in sorted(vars_dict):
        if is_secret:
            success(f"{key}={_MASK}")
        else:
            value = result.get(key, vars_dict[key])
            success(f"{key}={value}")


@config.command("get")
@click.argument("key")
@click.option("--app", "-a", "app_flag", default=None, help="Target app.")
@click.option("--reveal", is_flag=True, help="Unmask secret values.")
@click.pass_context
def get_cmd(
    ctx: click.Context,
    key: str,
    app_flag: str | None,
    reveal: bool,
) -> None:
    """Get a single config var."""
    parent_app = ctx.obj.get("_config_app")
    app_name = resolve_app(app_flag or parent_app)
    factory = ctx.obj["factory"]

    value, source = factory.config.get(app_name, key)
    display = value if reveal or source == "configmap" else _MASK
    click.echo(display)


@config.command("unset")
@click.argument("keys", nargs=-1, required=True)
@click.option("--app", "-a", "app_flag", default=None, help="Target app.")
@click.option("--no-restart", "no_restart", is_flag=True, help="Skip rolling restart.")
@click.pass_context
def unset_cmd(
    ctx: click.Context,
    keys: tuple[str, ...],
    app_flag: str | None,
    no_restart: bool,
) -> None:
    """Unset config vars."""
    parent_app = ctx.obj.get("_config_app")
    app_name = resolve_app(app_flag or parent_app)
    factory = ctx.obj["factory"]

    factory.config.unset(
        app_name, list(keys), no_restart=no_restart, on_step=lambda msg: info(msg)
    )
    for key in keys:
        success(f"Unset {key}.")
