from __future__ import annotations

import sys

from pathlib import Path

import click

from ai_rules.bootstrap import ToolSource
from ai_rules.cli.display import dim, print_hint


def _resolve_configured_source(configured: str | None) -> ToolSource | None:
    """Resolve a configured source string to a ToolSource enum value."""
    if configured and configured.startswith("local:"):
        return ToolSource.LOCAL
    if configured == "github":
        return ToolSource.GITHUB
    if configured == "pypi":
        return ToolSource.PYPI
    return None


def _format_source_display(source: ToolSource | None, configured: str | None) -> str:
    """Format combined source+config info for table display."""
    if not source:
        return dim("unknown")

    source_str = source.name.lower()
    configured_source = _resolve_configured_source(configured)

    if configured_source is not None and configured_source != source:
        return f"{source_str} [yellow](config: {configured} — run 'setup' to switch)[/yellow]"
    if configured is not None:
        if configured and configured.startswith("local:"):
            local_cfg_path = configured[len("local:") :]
            return f"{source_str} {dim(f'({local_cfg_path})')}"
        return f"{source_str} {dim('(config)')}"
    return source_str


def _format_config_display(source: ToolSource | None, configured: str) -> str:
    """Format config preference for detail display (tool show)."""
    configured_source = _resolve_configured_source(configured)
    if configured_source is not None and source and configured_source != source:
        return f"[yellow]{configured} (run 'setup' to switch)[/yellow]"
    return configured


@click.group()
def tool() -> None:
    """Manage tools and install source preferences."""
    pass


@tool.command("list")
def tool_list() -> None:
    """List managed tools with version and update info."""
    from rich.table import Table

    from ai_rules.bootstrap import (
        check_tool_updates,
        get_tool_source,
        get_updatable_tools,
    )
    from ai_rules.cli.display import console
    from ai_rules.config import Config

    try:
        config = Config.load()
    except Exception:
        config = None

    table = Table(title="Managed Tools", show_header=True)
    table.add_column("Tool", style="cyan")
    table.add_column("Source", style="bold")
    table.add_column("Version")
    table.add_column("Update")

    has_updates = False

    for spec in get_updatable_tools():
        if not spec.is_installed():
            table.add_row(spec.display_name, "-", "-", dim("(not installed)"))
            continue

        source = get_tool_source(spec.package_name)
        configured = config.get_tool_install_source(spec.tool_id) if config else None
        source_display = _format_source_display(source, configured)

        version = spec.get_version()
        version_display = version if version else dim("unknown")

        update_display = "-"
        try:
            update_info = check_tool_updates(spec, timeout=5)
            if update_info and update_info.has_update:
                update_display = f"[cyan]{update_info.latest_version} available[/cyan]"
                has_updates = True
            elif update_info and update_info.check_failed:
                update_display = dim("(check failed)")
        except Exception:
            update_display = dim("(check failed)")

        table.add_row(
            spec.display_name, source_display, version_display, update_display
        )

    console.print(table)

    if has_updates:
        from ai_rules.cli.display import print_hint

        print_hint("Run 'ai-agent-rules upgrade' to install updates.")


@tool.command("show")
@click.argument("tool_id")
def tool_show(tool_id: str) -> None:
    """Show detailed info for a managed tool.

    TOOL_ID can be one of: ai-agent-rules, ai-rules, statusline

    Examples:
        ai-agent-rules tool show statusline
        ai-agent-rules tool show ai-agent-rules
    """
    from ai_rules.bootstrap import (
        check_tool_updates,
        get_tool_source,
    )
    from ai_rules.bootstrap.updater import _TOOL_ID_ALIASES, get_tool_by_id
    from ai_rules.cli.display import console, print_error
    from ai_rules.config import Config

    canonical_id = _TOOL_ID_ALIASES.get(tool_id, tool_id)
    spec = get_tool_by_id(canonical_id)
    if spec is None:
        from ai_rules.bootstrap import get_updatable_tools

        valid_ids = ", ".join(sorted(t.tool_id for t in get_updatable_tools()))
        print_error(f"Unknown tool '{tool_id}'. Valid tools: {valid_ids}")
        sys.exit(1)

    console.print(f"[bold]{spec.display_name}[/bold]\n")

    if not spec.is_installed():
        console.print(f"  Status: {dim('not installed')}")
        return

    version = spec.get_version()
    console.print(f"  Version:  {version or dim('unknown')}")

    source = get_tool_source(spec.package_name)
    console.print(f"  Source:   {source.name.lower() if source else dim('unknown')}")

    try:
        config = Config.load()
        configured = config.get_tool_install_source(spec.tool_id)
    except Exception:
        configured = None
    if configured:
        config_display = _format_config_display(source, configured)
        console.print(f"  Config:   {config_display}")
    else:
        console.print(f"  Config:   {dim('(not set — default: pypi)')}")

    if spec.github_repo:
        console.print(f"  Repo:     https://github.com/{spec.github_repo}")

    try:
        update_info = check_tool_updates(spec, timeout=5)
        if update_info and update_info.has_update:
            console.print(
                f"  Update:   [cyan]{update_info.latest_version} available[/cyan]"
            )
        elif update_info and update_info.check_failed:
            console.print(f"  Update:   {dim('(check failed)')}")
        elif update_info:
            console.print("  Update:   [green]up to date[/green]")
    except Exception:
        console.print(f"  Update:   {dim('(check failed)')}")


@tool.group()
def source() -> None:
    """Manage install source preferences."""
    pass


@source.command("list")
def source_list() -> None:
    """List install source preferences for all tools.

    Examples:
        ai-agent-rules tool source list
    """
    from rich.table import Table

    from ai_rules.bootstrap.updater import get_updatable_tools
    from ai_rules.cli.display import console
    from ai_rules.config import Config

    tools = get_updatable_tools()
    table = Table(title="Tool Install Source Preferences", show_header=True)
    table.add_column("Tool", style="cyan")
    table.add_column("User Config")
    table.add_column("Effective (from profile/config)")

    for spec in tools:
        user_pref = Config.get_tool_install_source_from_user_config(spec.tool_id)
        try:
            effective_pref = Config.load().get_tool_install_source(spec.tool_id)
        except Exception:
            effective_pref = None
        table.add_row(
            spec.tool_id,
            user_pref or dim("(not set)"),
            effective_pref or dim("(default: pypi)"),
        )
    console.print(table)
    print_hint(
        "Run 'ai-agent-rules setup' after changing to switch the installed source."
    )


def _resolve_tool_id(tool_id: str) -> str:
    """Resolve a tool ID alias to canonical form, or exit with an error."""
    from ai_rules.bootstrap.updater import _TOOL_ID_ALIASES, get_updatable_tools

    canonical_id = _TOOL_ID_ALIASES.get(tool_id, tool_id)
    valid_ids = {t.tool_id for t in get_updatable_tools()}
    if canonical_id not in valid_ids:
        from ai_rules.cli.display import print_error

        print_error(
            f"Unknown tool '{tool_id}'. Valid tools: {', '.join(sorted(valid_ids))}"
        )
        sys.exit(1)
    return canonical_id


@source.command("get")
@click.argument("tool_id")
def source_get(tool_id: str) -> None:
    """Show the install source preference for a tool.

    TOOL_ID can be one of: ai-agent-rules, ai-rules, statusline

    Examples:
        ai-agent-rules tool source get statusline
    """
    from ai_rules.cli.display import console
    from ai_rules.config import Config

    canonical_id = _resolve_tool_id(tool_id)

    user_pref = Config.get_tool_install_source_from_user_config(canonical_id)
    try:
        effective_pref = Config.load().get_tool_install_source(canonical_id)
    except Exception:
        effective_pref = None

    if user_pref:
        console.print(
            f"[cyan]{canonical_id}[/cyan] user config: [bold]{user_pref}[/bold]"
        )
    else:
        console.print(f"[cyan]{canonical_id}[/cyan] user config: {dim('(not set)')}")
    if effective_pref:
        console.print(
            f"[cyan]{canonical_id}[/cyan] effective (profile/config): [bold]{effective_pref}[/bold]"
        )
    else:
        console.print(
            f"[cyan]{canonical_id}[/cyan] effective: {dim('(default: pypi)')}"
        )


@source.command("set")
@click.argument("tool_id")
@click.argument("source_value")
def source_set(tool_id: str, source_value: str) -> None:
    """Set the install source preference for a tool.

    TOOL_ID can be one of: ai-agent-rules, ai-rules, statusline

    SOURCE_VALUE can be: pypi, github, local:<path>, or reset

    Examples:
        ai-agent-rules tool source set statusline github
        ai-agent-rules tool source set ai-agent-rules "local:~/Development/Personal/ai-rules"
        ai-agent-rules tool source set statusline reset
    """
    from ai_rules.cli.display import print_error, print_success
    from ai_rules.config import Config

    canonical_id = _resolve_tool_id(tool_id)

    if source_value == "reset":
        Config.set_tool_install_source(canonical_id, None)
        print_success(
            f"Cleared install source preference for [cyan]{canonical_id}[/cyan]"
        )
    elif source_value in ("pypi", "github"):
        Config.set_tool_install_source(canonical_id, source_value)
        print_success(
            f"Set [cyan]{canonical_id}[/cyan] install source to [bold]{source_value}[/bold]"
        )
        print_hint(
            "Run 'ai-agent-rules setup' to switch the installed source if needed."
        )
    elif source_value.startswith("local:"):
        local_path = source_value[len("local:") :]
        resolved = Path(local_path).expanduser().resolve()
        if not resolved.exists():
            print_error(f"Path does not exist: {resolved}")
            sys.exit(1)
        Config.set_tool_install_source(canonical_id, f"local:{resolved}")
        print_success(
            f"Set [cyan]{canonical_id}[/cyan] install source to [bold]local: {resolved}[/bold]"
        )
        print_hint("Run 'ai-agent-rules install' to install from local path.")
    else:
        print_error(
            f"Invalid source value '{source_value}'. Use: pypi, github, local:<path>, or reset"
        )
        sys.exit(1)
