"""
Module: config_cmd
Description: Configuration management commands

Implements:
    - docs/cli/reference.md#huitzo-config
"""

from typing import Any

import typer
from rich.table import Table

from huitzo_cli.auth import AuthClient, TokenStore
from huitzo_cli.config import ConfigManager
from huitzo_cli.interactive import guarded_prompt
from huitzo_cli.output import get_output

config_app = typer.Typer(help="Manage configuration")

_SENSITIVE_PATTERNS = ("token", "secret", "key", "password", "credential")


def _is_sensitive(key: str) -> bool:
    k = key.lower()
    return any(p in k for p in _SENSITIVE_PATTERNS)


@config_app.callback(invoke_without_command=True)
def config_callback(ctx: typer.Context) -> None:
    """Manage configuration - get, set, list, and view config files."""
    if ctx.invoked_subcommand is None:
        output = get_output(ctx)
        output.print(ctx.get_help())
        raise typer.Exit(0)


@config_app.command()
def get(
    ctx: typer.Context,
    key: str = typer.Argument(...),
    reveal: bool = typer.Option(False, "--reveal", help="Show sensitive values unmasked"),
) -> None:
    """Get configuration value.

    Args:
        key: Configuration key (e.g., 'api_url' or 'auth.token')
    """
    output = get_output(ctx)

    # auth.token lives in TokenStore, not config.yaml
    if key == "auth.token":
        config = ConfigManager()
        auth = AuthClient(config)
        value = auth.get_token()
        if value is None:
            output.print("[yellow]Not authenticated. Run: huitzo login[/yellow]")
            raise typer.Exit(1)
        display = "********" if not reveal else value
        output.print(f"{key} = {display}")
        output.success({"key": key, "value": value if reveal else "********"})
        return

    config = ConfigManager()
    value = config.get(key)

    if value is None:
        output.print(f"[yellow]{key} not set[/yellow]")
        raise typer.Exit(1)

    if _is_sensitive(key) and not reveal:
        display = "********"
    else:
        display = value
    output.print(f"{key} = {display}")
    output.success({"key": key, "value": display})


@config_app.command()
def set(
    ctx: typer.Context,
    key: str = typer.Argument(...),
    value: str | None = typer.Argument(None, help="Value to set (prompted for sensitive keys)"),
    scope: str = typer.Option("user", "--scope", help="Config scope (user or project)"),
) -> None:
    """Set configuration value.

    For sensitive keys (containing 'token', 'secret', 'key', 'password',
    'credential'), the value is always prompted interactively with hidden
    input to prevent exposure in shell history.

    Args:
        key: Configuration key (e.g., 'auth.token')
        value: Value to set (ignored for sensitive keys)
    """
    output = get_output(ctx)

    # auth.token is stored in TokenStore, not config.yaml
    if key == "auth.token":
        output.print("[yellow]Prefer 'huitzo login' to set auth tokens.[/yellow]")
        # Always prompt interactively — ignore positional arg to avoid shell history leak
        token_value = guarded_prompt(ctx, f"Value for {key}", hide_input=True)
        TokenStore().save(token_value)
        output.print(f"[green]{key} updated[/green]")
        output.success({"key": key, "updated": True})
        return

    config = ConfigManager()

    if _is_sensitive(key):
        # Always prompt interactively for sensitive keys
        value = guarded_prompt(ctx, f"Value for {key}", hide_input=True)
    elif value is None:
        value = guarded_prompt(ctx, f"Value for {key}")

    try:
        config.set(key, value, scope=scope)
        if _is_sensitive(key):
            output.print(f"[green]{key} updated[/green]")
        else:
            output.print(f"[green]{key} set to {value}[/green]")
        output.success({"key": key, "value": value if not _is_sensitive(key) else "********"})
    except Exception as e:
        output.error("ConfigError", f"Failed to set {key}: {e}", 1)
        raise typer.Exit(1)


@config_app.command(name="list")
def list_config(ctx: typer.Context) -> None:
    """List all configuration."""
    output = get_output(ctx)
    config = ConfigManager()
    config_dict = config.to_dict()

    table = Table(title="Configuration")
    table.add_column("Key", style="cyan")
    table.add_column("Value", style="green")

    def flatten_dict(d: dict[str, Any], parent_key: str = "") -> list[tuple[str, str]]:
        items = []
        for k, v in d.items():
            new_key = f"{parent_key}.{k}" if parent_key else k
            if isinstance(v, dict):
                items.extend(flatten_dict(v, new_key))
            else:
                items.append((new_key, str(v)))
        return items

    flat = flatten_dict(config_dict)
    for key, value in flat:
        display = "********" if _is_sensitive(key) else value
        table.add_row(key, display)

    output.print(table)
    output.success({"config": {k: ("********" if _is_sensitive(k) else v) for k, v in flat}})


@config_app.command()
def path(
    ctx: typer.Context,
    scope: str = typer.Option("user", "--scope", help="Config scope (user or project)"),
) -> None:
    """Show configuration file path.

    Args:
        scope: Config scope (user or project)
    """
    output = get_output(ctx)
    config = ConfigManager()
    config_path = config.get_config_path(scope=scope)
    output.print(f"[cyan]{scope.capitalize()} config:[/cyan] {config_path}")
    output.print(f"[yellow]Exists:[/yellow] {config_path.exists()}")
    output.success({"scope": scope, "path": str(config_path), "exists": config_path.exists()})
