import click

from strawhub.commands.install import _install_impl, _slug_installed_in_scope
from strawhub.display import print_success, print_error, console
from strawhub.lockfile import Lockfile
from strawhub.paths import (
    get_root,
    get_local_root,
    get_lockfile_path,
    get_project_file_path,
)
from strawhub.project_file import ProjectFile


@click.group(invoke_without_command=True)
@click.option(
    "--all",
    "update_all",
    is_flag=True,
    default=False,
    help="Update all installed packages",
)
@click.option(
    "--global",
    "is_global",
    is_flag=True,
    default=False,
    help="Update global packages (~/.strawpot or STRAWPOT_HOME)",
)
@click.option(
    "--skip-tools",
    is_flag=True,
    default=False,
    help="Skip running system tool install commands",
)
@click.option(
    "--yes", "-y",
    is_flag=True,
    default=False,
    help="Automatically confirm tool install commands without prompting",
)
@click.option(
    "--save",
    is_flag=True,
    default=False,
    help="Update version constraints in strawpot.toml to match installed versions",
)
@click.option(
    "--type",
    "kind_filter",
    type=click.Choice(["role", "skill", "agent", "memory", "integration"], case_sensitive=False),
    default=None,
    help="Only update packages of this type (used with --all)",
)
@click.pass_context
def update(ctx, update_all, is_global, skip_tools, yes, save, kind_filter):
    """Update installed skills/roles/agents/memories/integrations to their latest versions."""
    if save and is_global:
        print_error("--save cannot be used with --global")
        raise SystemExit(1)
    if kind_filter and not update_all:
        print_error("--type requires --all")
        raise SystemExit(1)
    if update_all:
        _update_all_impl(is_global, skip_tools=skip_tools, yes=yes, save=save, kind_filter=kind_filter)
        return
    if ctx.invoked_subcommand is None:
        click.echo("Specify 'skill <slug>', 'role <slug>', 'agent <slug>', 'memory <slug>', 'integration <slug>', or use --all.")
        ctx.exit(1)


def _save_updated_version(kind: str, slug: str) -> None:
    """Update strawpot.toml constraint for a package to its current installed version."""
    pf = ProjectFile.load(get_project_file_path())
    if not pf.has_dependency(kind, slug):
        return
    version = _slug_installed_in_scope(get_local_root(), kind, slug)
    if version and pf.update_dependency(kind, slug, version):
        pf.save()
        constraint = pf.get_constraint(kind, slug)
        console.print(f"Updated '{slug}' to {constraint} in strawpot.toml")


def _update_all_impl(is_global, skip_tools=False, yes=False, save=False, kind_filter=None):
    from strawhub.paths import _local_root_override

    if is_global and _local_root_override is not None:
        print_error("--root and --global cannot be used together")
        raise SystemExit(1)

    root = get_root(is_global)
    lockfile = Lockfile.load(get_lockfile_path(root))

    refs = list(lockfile.direct_installs)
    if kind_filter:
        refs = [r for r in refs if r.kind == kind_filter]

    if not refs:
        label = f" {kind_filter}" if kind_filter else ""
        click.echo(f"No{label} packages to update.")
        return

    for ref in refs:
        _install_impl(
            ref.slug,
            kind=ref.kind,
            is_global=is_global,
            skip_tools=skip_tools,
            yes=yes,
            update=True,
        )
        if save:
            _save_updated_version(ref.kind, ref.slug)


def _update_one_impl(slug, kind, is_global, skip_tools=False, yes=False, save=False):
    from strawhub.paths import _local_root_override

    if is_global and _local_root_override is not None:
        print_error("--root and --global cannot be used together")
        raise SystemExit(1)
    if save and is_global:
        print_error("--save cannot be used with --global")
        raise SystemExit(1)
    _install_impl(
        slug,
        kind=kind,
        is_global=is_global,
        skip_tools=skip_tools,
        yes=yes,
        update=True,
    )
    if save:
        _save_updated_version(kind, slug)


@update.command("skill")
@click.argument("slug")
@click.option("--global", "is_global", is_flag=True, default=False, help="Update global packages (~/.strawpot or STRAWPOT_HOME)")
@click.option("--skip-tools", is_flag=True, default=False, help="Skip running system tool install commands")
@click.option("--yes", "-y", is_flag=True, default=False, help="Automatically confirm tool install commands without prompting")
@click.option("--save", is_flag=True, default=False, help="Update version constraint in strawpot.toml")
def update_skill(slug, is_global, skip_tools, yes, save):
    """Update an installed skill to its latest version."""
    _update_one_impl(slug, kind="skill", is_global=is_global, skip_tools=skip_tools, yes=yes, save=save)


@update.command("role")
@click.argument("slug")
@click.option("--global", "is_global", is_flag=True, default=False, help="Update global packages (~/.strawpot or STRAWPOT_HOME)")
@click.option("--skip-tools", is_flag=True, default=False, help="Skip running system tool install commands")
@click.option("--yes", "-y", is_flag=True, default=False, help="Automatically confirm tool install commands without prompting")
@click.option("--save", is_flag=True, default=False, help="Update version constraint in strawpot.toml")
def update_role(slug, is_global, skip_tools, yes, save):
    """Update an installed role to its latest version."""
    _update_one_impl(slug, kind="role", is_global=is_global, skip_tools=skip_tools, yes=yes, save=save)


@update.command("agent")
@click.argument("slug")
@click.option("--global", "is_global", is_flag=True, default=False, help="Update global packages (~/.strawpot or STRAWPOT_HOME)")
@click.option("--yes", "-y", is_flag=True, default=False, help="Automatically confirm tool install commands without prompting")
@click.option("--save", is_flag=True, default=False, help="Update version constraint in strawpot.toml")
def update_agent(slug, is_global, yes, save):
    """Update an installed agent to its latest version."""
    _update_one_impl(slug, kind="agent", is_global=is_global, yes=yes, save=save)


@update.command("memory")
@click.argument("slug")
@click.option("--global", "is_global", is_flag=True, default=False, help="Update global packages (~/.strawpot or STRAWPOT_HOME)")
@click.option("--yes", "-y", is_flag=True, default=False, help="Automatically confirm tool install commands without prompting")
@click.option("--save", is_flag=True, default=False, help="Update version constraint in strawpot.toml")
def update_memory(slug, is_global, yes, save):
    """Update an installed memory to its latest version."""
    _update_one_impl(slug, kind="memory", is_global=is_global, yes=yes, save=save)


@update.command("integration")
@click.argument("slug")
@click.option("--global", "is_global", is_flag=True, default=False, help="Update global packages (~/.strawpot or STRAWPOT_HOME)")
@click.option("--yes", "-y", is_flag=True, default=False, help="Automatically confirm tool install commands without prompting")
@click.option("--save", is_flag=True, default=False, help="Update version constraint in strawpot.toml")
def update_integration(slug, is_global, yes, save):
    """Update an installed integration to its latest version."""
    _update_one_impl(slug, kind="integration", is_global=is_global, yes=yes, save=save)
