"""Configuration management commands for agent-cli."""

from __future__ import annotations

import json
import os
import platform
import shlex
import shutil
import subprocess
from importlib import resources
from pathlib import Path  # noqa: TC003

import typer

from agent_cli.cli import app
from agent_cli.config import CONFIG_PATHS, USER_CONFIG_PATH, _config_path
from agent_cli.core.process import set_process_title
from agent_cli.core.utils import console

config_app = typer.Typer(
    name="config",
    help="""Manage agent-cli configuration files.

Config files are TOML format and searched in order:

1. `$AGENT_CLI_CONFIG_HOME/config.toml` (if set)
2. `./agent-cli-config.toml` (project-local)
3. `$XDG_CONFIG_HOME/agent-cli/config.toml` (if set)
4. `~/.config/agent-cli/config.toml` (user default)

Settings in `[defaults]` apply globally.

Use `[chat]` or `[transcribe]` for command-specific overrides.

CLI arguments override config file settings.

Set env vars before startup.

Use `$AGENT_CLI_CONFIG_HOME` or `$XDG_CONFIG_HOME` to change config path.
""",
    add_completion=True,
    rich_markup_mode="markdown",
    no_args_is_help=True,
)
app.add_typer(config_app, name="config", rich_help_panel="Configuration")


@config_app.callback()
def config_callback(ctx: typer.Context) -> None:
    """Config command group callback."""
    if ctx.invoked_subcommand is not None:
        set_process_title(f"config-{ctx.invoked_subcommand}")


# --- Config command options ---
CONFIG_PATH_OPTION: Path | None = typer.Option(
    None,
    "--path",
    "-p",
    help="Override auto-detection and use this config file path.",
)
CONFIG_PATH_INIT_OPTION: Path | None = typer.Option(
    None,
    "--path",
    "-p",
    help="Where to create the config file (default: resolved user config path).",
)
FORCE_OPTION: bool = typer.Option(
    False,  # noqa: FBT003
    "--force",
    "-f",
    help="Overwrite existing config without prompting for confirmation.",
)
RAW_OPTION: bool = typer.Option(
    False,  # noqa: FBT003
    "--raw",
    "-r",
    help="Print plain file contents without syntax highlighting or line numbers.",
)
JSON_OPTION: bool = typer.Option(
    False,  # noqa: FBT003
    "--json",
    help="Output as JSON with `path`, `exists`, and `content` fields.",
)


def _get_editor() -> str:
    """Get the user's preferred editor.

    Checks $EDITOR, then $VISUAL, then falls back to platform defaults.
    """
    for env_var in ("EDITOR", "VISUAL"):
        editor = os.environ.get(env_var)
        if editor:
            return editor

    if platform.system() == "Windows":
        return "notepad"

    # Try common editors on Unix-like systems
    for editor in ("nano", "vim", "vi"):
        if shutil.which(editor):
            return editor

    return "vi"


def _generate_template() -> str:
    """Generate a config template with all options commented out."""
    header = """\
# agent-cli configuration file
# Generated by: agent-cli config init
#
# Uncomment and modify options as needed.
# Keys use dashes to match command-line arguments.
# Any option here can be overridden by a command-line argument.
#
# For full documentation, see: https://github.com/basnijholt/agent-cli
"""

    # Example config is bundled with the package
    try:
        template_file = resources.files(__package__) / "example-config.toml"
        example_content = template_file.read_text(encoding="utf-8")
    except FileNotFoundError as e:
        console.print("[red]Example config template is missing from the package.[/red]")
        console.print("Reinstall agent-cli or report this issue.")
        raise typer.Exit(1) from e

    lines = [header.rstrip()]
    skip_header = True  # Skip the original file's header comments

    for line in example_content.splitlines():
        stripped = line.strip()

        # Skip the original header comments (lines before first section)
        if skip_header:
            if stripped.startswith("["):
                skip_header = False
            else:
                continue

        # Keep section headers [defaults], [chat], etc.
        if (
            (stripped.startswith("[") and stripped.endswith("]"))
            or stripped.startswith("#")
            or not stripped
        ):
            lines.append(line)
        # Comment out actual config values
        else:
            lines.append(f"# {line}")

    return "\n".join(lines) + "\n"


def _get_config_file(path: Path | None) -> Path | None:
    """Resolve config path, or auto-detect from standard locations."""
    if path:
        return path.expanduser().resolve()
    return _config_path(None)


@config_app.command("init")
def config_init(
    path: Path | None = CONFIG_PATH_INIT_OPTION,
    force: bool = FORCE_OPTION,
) -> None:
    """Create a new config file with all options as commented-out examples.

    Generates a TOML template with `[defaults]` for global settings and
    command-specific sections like `[chat]`, `[transcribe]`, etc. Uncomment
    and edit the options you want to customize.

    Example: `agent-cli config init && agent-cli config edit`
    """
    target_path = _get_config_file(path) or USER_CONFIG_PATH

    if target_path.exists() and not force:
        console.print(
            f"[bold yellow]Config file already exists at:[/bold yellow] [cyan]{target_path}[/cyan]",
        )
        if not typer.confirm("Overwrite existing config file?"):
            console.print("[dim]Aborted.[/dim]")
            raise typer.Exit(0)

    # Create parent directories
    target_path.parent.mkdir(parents=True, exist_ok=True)

    # Generate and write template
    template_content = _generate_template()
    target_path.write_text(template_content, encoding="utf-8")

    console.print(f"[green]Config file created at:[/green] {target_path}")
    console.print("\n[dim]Edit the file to customize your settings:[/dim]")
    console.print("  [cyan]agent-cli config edit[/cyan]")


@config_app.command("edit")
def config_edit(
    path: Path | None = CONFIG_PATH_OPTION,
) -> None:
    """Open the config file in your default editor.

    Editor preference: `$EDITOR` → `$VISUAL` → `nano`/`vim` → `vi` (or
    `notepad` on Windows). If no config exists, run `agent-cli config init`
    first.
    """
    config_file = _get_config_file(path)

    if config_file is None:
        console.print("[yellow]No config file found.[/yellow]")
        console.print(
            "\nRun [bold cyan]agent-cli config init[/bold cyan] to create one.",
        )
        console.print("\nSearched locations:")
        for p in CONFIG_PATHS:
            console.print(f"  - {p}")
        raise typer.Exit(1)

    if not config_file.exists():
        console.print("[yellow]Config file not found.[/yellow]")
        console.print(f"\nProvided path does not exist: [cyan]{config_file}[/cyan]")
        console.print(
            "\nRun [bold cyan]agent-cli config init[/bold cyan] to create one.",
        )
        raise typer.Exit(1)

    editor = _get_editor()
    console.print(f"[dim]Opening {config_file} with {editor}...[/dim]")

    try:
        editor_cmd = shlex.split(editor, posix=os.name != "nt")
    except ValueError as e:
        console.print("[red]Invalid editor command. Check $EDITOR/$VISUAL.[/red]")
        raise typer.Exit(1) from e

    if not editor_cmd:
        console.print("[red]Editor command is empty.[/red]")
        raise typer.Exit(1)

    try:
        subprocess.run([*editor_cmd, str(config_file)], check=True)
    except FileNotFoundError:
        console.print(f"[red]Editor '{editor_cmd[0]}' not found.[/red]")
        console.print("Set $EDITOR environment variable to your preferred editor.")
        raise typer.Exit(1) from None
    except subprocess.CalledProcessError as e:
        console.print(f"[red]Editor exited with error code {e.returncode}[/red]")
        raise typer.Exit(e.returncode) from None


@config_app.command("show")
def config_show(
    path: Path | None = CONFIG_PATH_OPTION,
    raw: bool = RAW_OPTION,
    json_output: bool = JSON_OPTION,
) -> None:
    """Display the active config file path and contents.

    By default, shows syntax-highlighted TOML with line numbers. Use `--raw`
    for plain output (useful for piping), or `--json` for programmatic access.
    """
    config_file = _get_config_file(path)

    if config_file is None:
        if json_output:
            print(
                json.dumps(
                    {
                        "path": None,
                        "exists": False,
                        "content": None,
                        "searched_locations": [str(p) for p in CONFIG_PATHS],
                    },
                ),
            )
            raise typer.Exit(0)
        console.print("[yellow]No config file found.[/yellow]")
        console.print("\nSearched locations:")
        for p in CONFIG_PATHS:
            status = "[green]exists[/green]" if p.exists() else "[dim]not found[/dim]"
            console.print(f"  - {p} ({status})")
        console.print(
            "\nRun [bold cyan]agent-cli config init[/bold cyan] to create one.",
        )
        raise typer.Exit(0)

    if not config_file.exists():
        if json_output:
            print(
                json.dumps(
                    {
                        "path": str(config_file),
                        "exists": False,
                        "content": None,
                    },
                ),
            )
            raise typer.Exit(1)
        console.print("[yellow]Config file not found.[/yellow]")
        console.print(f"\nProvided path does not exist: [cyan]{config_file}[/cyan]")
        console.print(
            "\nRun [bold cyan]agent-cli config init[/bold cyan] to create one.",
        )
        raise typer.Exit(1)

    content = config_file.read_text(encoding="utf-8")

    if json_output:
        print(
            json.dumps(
                {
                    "path": str(config_file),
                    "exists": True,
                    "content": content,
                },
            ),
        )
        return

    if raw:
        print(content, end="")
        return

    from rich.syntax import Syntax  # noqa: PLC0415

    console.print(f"[bold green]Config file:[/bold green] [cyan]{config_file}[/cyan]")
    console.print()
    syntax = Syntax(content, "toml", theme="monokai", line_numbers=True, word_wrap=True)
    console.print(syntax)
    console.print()
    console.print("[dim]Tip: Use -r for copy-paste friendly output[/dim]")
