import shutil

import click

from strawhub.display import print_success, print_error, console
from strawhub.lockfile import Lockfile, PackageRef
from strawhub.logging import log_operation
from strawhub.paths import (
    get_root,
    get_lockfile_path,
    get_package_dir,
    get_project_file_path,
)
from strawhub.project_file import ProjectFile


@click.group(invoke_without_command=True)
@click.pass_context
def uninstall(ctx):
    """Remove an installed skill, role, agent, memory, or integration and clean up orphaned dependencies."""
    if ctx.invoked_subcommand is None:
        click.echo(ctx.get_help())
        ctx.exit(1)


def _uninstall_impl(slug, kind, ver, is_global, 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)

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

    if not lockfile.packages:
        print_error("No packages installed (lockfile is empty).")
        log_operation(
            operation="uninstall", kind=kind, slug=slug, version=ver,
            status="failure", error="lockfile is empty",
        )
        raise SystemExit(1)

    # Find matching direct installs
    targets = _find_targets(lockfile, slug, kind, ver)
    if not targets:
        print_error(f"'{slug}' is not a direct install. Nothing to remove.")
        log_operation(
            operation="uninstall", kind=kind, slug=slug, version=ver,
            status="failure", error="not a direct install",
        )
        raise SystemExit(1)

    # Remove each target from direct installs
    for ref in targets:
        lockfile.remove_direct_install(ref)
        console.print(f"Removed {ref.kind} '{ref.slug}' v{ref.version} from direct installs")

    # Collect orphans (cascading)
    orphans = lockfile.collect_orphans()

    # Remove orphaned packages from disk and lockfile
    for key in orphans:
        pkg = lockfile.packages.get(key)
        if not pkg:
            continue
        pkg_dir = get_package_dir(root, pkg["kind"], pkg["slug"])
        if pkg_dir.is_dir():
            shutil.rmtree(pkg_dir)
        lockfile.remove_package(key)
        console.print(f"  Removed {pkg['kind']} '{pkg['slug']}' v{pkg['version']}")

    lockfile.save()

    # Remove from project file if requested
    if save:
        pf = ProjectFile.load(get_project_file_path())
        if pf.remove_dependency(kind, slug):
            pf.save()
            console.print(f"Removed '{slug}' from strawpot.toml")

    print_success("Uninstall complete.")
    for ref in targets:
        log_operation(
            operation="uninstall",
            kind=ref.kind,
            slug=ref.slug,
            version=ref.version,
            status="success",
        )


@uninstall.command("skill")
@click.argument("slug")
@click.option("--version", "ver", default=None, help="Specific version to remove (removes all versions if omitted)")
@click.option("--global", "is_global", is_flag=True, default=False, help="Remove from global directory (~/.strawpot or STRAWPOT_HOME)")
@click.option("--save", is_flag=True, default=False, help="Also remove from strawpot.toml")
def uninstall_skill(slug, ver, is_global, save):
    """Remove an installed skill and clean up orphaned dependencies."""
    _uninstall_impl(slug, kind="skill", ver=ver, is_global=is_global, save=save)


@uninstall.command("role")
@click.argument("slug")
@click.option("--version", "ver", default=None, help="Specific version to remove (removes all versions if omitted)")
@click.option("--global", "is_global", is_flag=True, default=False, help="Remove from global directory (~/.strawpot or STRAWPOT_HOME)")
@click.option("--save", is_flag=True, default=False, help="Also remove from strawpot.toml")
def uninstall_role(slug, ver, is_global, save):
    """Remove an installed role and clean up orphaned dependencies."""
    _uninstall_impl(slug, kind="role", ver=ver, is_global=is_global, save=save)


@uninstall.command("agent")
@click.argument("slug")
@click.option("--version", "ver", default=None, help="Specific version to remove (removes all versions if omitted)")
@click.option("--global", "is_global", is_flag=True, default=False, help="Remove from global directory (~/.strawpot or STRAWPOT_HOME)")
@click.option("--save", is_flag=True, default=False, help="Also remove from strawpot.toml")
def uninstall_agent(slug, ver, is_global, save):
    """Remove an installed agent and clean up orphaned dependencies."""
    _uninstall_impl(slug, kind="agent", ver=ver, is_global=is_global, save=save)


@uninstall.command("memory")
@click.argument("slug")
@click.option("--version", "ver", default=None, help="Specific version to remove (removes all versions if omitted)")
@click.option("--global", "is_global", is_flag=True, default=False, help="Remove from global directory (~/.strawpot or STRAWPOT_HOME)")
@click.option("--save", is_flag=True, default=False, help="Also remove from strawpot.toml")
def uninstall_memory(slug, ver, is_global, save):
    """Remove an installed memory and clean up orphaned dependencies."""
    _uninstall_impl(slug, kind="memory", ver=ver, is_global=is_global, save=save)


@uninstall.command("integration")
@click.argument("slug")
@click.option("--version", "ver", default=None, help="Specific version to remove (removes all versions if omitted)")
@click.option("--global", "is_global", is_flag=True, default=False, help="Remove from global directory (~/.strawpot or STRAWPOT_HOME)")
@click.option("--save", is_flag=True, default=False, help="Also remove from strawpot.toml")
def uninstall_integration(slug, ver, is_global, save):
    """Remove an installed integration."""
    _uninstall_impl(slug, kind="integration", ver=ver, is_global=is_global, save=save)


def _find_targets(
    lockfile: Lockfile, slug: str, kind: str, ver: str | None
) -> list[PackageRef]:
    """Find direct installs matching the given criteria."""
    targets = []
    for ref in lockfile.direct_installs:
        if ref.slug != slug:
            continue
        if ref.kind != kind:
            continue
        if ver and ref.version != ver:
            continue
        targets.append(ref)
    return targets
