"""CLI commands for clusters:* — add, remove, switch, current, info, doctor, setup."""

from __future__ import annotations

import click

from kuberoku.cli.output import info, render_detail, success
from kuberoku.sdk.clusters import detect_kubeconfig_context


class _ColonGroup(click.Group):
    """Nested ColonCommandGroup for clusters subcommands."""

    def resolve_command(
        self, ctx: click.Context, args: list[str]
    ) -> tuple[str | None, click.Command | None, list[str]]:
        cmd_name = args[0] if args else None
        if cmd_name and ":" in cmd_name:
            parts = cmd_name.split(":", 1)
            args = [parts[0], parts[1]] + args[1:]
        return super().resolve_command(ctx, args)


@click.group("clusters", cls=_ColonGroup, invoke_without_command=True)
@click.pass_context
def clusters(ctx: click.Context) -> None:
    """Manage clusters."""
    if ctx.invoked_subcommand is None:
        factory = ctx.obj["factory"]
        cluster_list = factory.clusters.list()
        if not cluster_list:
            # No registered clusters — show auto-detected kubeconfig context
            ctx_name, cluster_name = detect_kubeconfig_context()
            if ctx_name is None:
                info("No Kubernetes cluster found.")
                info("Configure kubectl first, then try again.")
                return
            click.echo(f"  * {ctx_name}  (auto-detected from kubeconfig)")
            if cluster_name and cluster_name != ctx_name:
                click.echo(f"    cluster: {cluster_name}")
            click.echo(f"    namespace: {factory.namespace}")
            click.echo("")
            info("Use 'clusters:add' to register named clusters for multi-cluster workflows.")
            return
        # Show current cluster marker
        try:
            current = factory.clusters.current()
        except Exception:
            current = None
        for c in cluster_list:
            marker = "*" if c.name == current else " "
            ns_info = f" (namespace: {c.namespace})" if c.namespace else ""
            click.echo(f"  {marker} {c.name}  context={c.context}{ns_info}")


@clusters.command()
@click.argument("name")
@click.option("--context", "ctx_name", required=True, help="kubeconfig context name.")
@click.option("--namespace", default=None, help="K8s namespace for this cluster.")
@click.option("--default", "is_default", is_flag=True, help="Set as default cluster.")
@click.pass_context
def add(
    ctx: click.Context,
    name: str,
    ctx_name: str,
    namespace: str | None,
    is_default: bool,
) -> None:
    """Register a cluster."""
    factory = ctx.obj["factory"]
    cluster = factory.clusters.add(
        name,
        ctx_name,
        namespace=namespace,
        default=is_default,
        on_step=lambda msg: info(msg),
    )
    success(f"Added cluster {cluster.name} (context={cluster.context}).")


@clusters.command()
@click.argument("name")
@click.option("--confirm", "confirm_name", default=None, help="Confirm cluster name.")
@click.pass_context
def remove(ctx: click.Context, name: str, confirm_name: str | None) -> None:
    """Unregister a cluster."""
    if confirm_name != name and not click.confirm(f"Remove cluster '{name}'?"):
        info("Aborted.")
        return
    factory = ctx.obj["factory"]
    factory.clusters.remove(name, on_step=lambda msg: info(msg))
    success(f"Removed cluster {name}.")


@clusters.command()
@click.argument("name")
@click.pass_context
def switch(ctx: click.Context, name: str) -> None:
    """Switch active cluster."""
    factory = ctx.obj["factory"]
    factory.clusters.switch(name, on_step=lambda msg: info(msg))
    success(f"Switched to cluster {name}.")


@clusters.command("current")
@click.pass_context
def current_cmd(ctx: click.Context) -> None:
    """Show the current cluster."""
    factory = ctx.obj["factory"]
    name = factory.clusters.current()
    click.echo(name)


@clusters.command("info")
@click.argument("name")
@click.pass_context
def info_cmd(ctx: click.Context, name: str) -> None:
    """Show details about a cluster."""
    factory = ctx.obj["factory"]
    cluster_info = factory.clusters.info(name, on_step=lambda msg: info(msg))
    render_detail(
        cluster_info.name,
        {
            "Context": cluster_info.context,
            "Current": "yes" if cluster_info.is_current else "no",
            "K8s version": cluster_info.k8s_version or "(unknown)",
            "Nodes": (
                str(cluster_info.node_count)
                if cluster_info.node_count is not None
                else "(unknown)"
            ),
            "Apps": (
                str(cluster_info.app_count) if cluster_info.app_count is not None else "(unknown)"
            ),
        },
    )


@clusters.command("doctor")
@click.option("--fix", "fix_rbac", is_flag=True, help="Generate RBAC fix YAML.")
@click.pass_context
def doctor(ctx: click.Context, fix_rbac: bool) -> None:
    """Quick cluster health check."""
    factory = ctx.obj["factory"]

    if fix_rbac:
        fix_yaml = factory.doctor.generate_rbac_fix(on_step=lambda msg: info(msg))
        if fix_yaml.missing_count == 0:
            success("All RBAC permissions are already granted.")
            return
        click.echo(f"# Missing {fix_yaml.missing_count} RBAC rule(s). Apply with:")
        click.echo("# kubectl apply -f <file>")
        click.echo("---")
        click.echo(fix_yaml.role_yaml, nl=False)
        click.echo("---")
        click.echo(fix_yaml.rolebinding_yaml, nl=False)
        return

    checks = factory.doctor.run_checks(on_step=lambda msg: info(msg))

    click.echo("")
    for i, check in enumerate(checks, start=1):
        marker = "+" if check.passed else "!"
        click.echo(f"  [{marker}] {i}. {check.message}")

    click.echo("")
    passed = sum(1 for c in checks if c.passed)
    total = len(checks)
    if all(c.passed for c in checks):
        success(f"All {total} checks passed.")
    else:
        failed = total - passed
        click.echo(f"{passed}/{total} checks passed, {failed} failed.")
        click.echo("Run 'clusters:setup' to fix.")
        ctx.exit(1)


@clusters.command("setup")
@click.pass_context
def setup(ctx: click.Context) -> None:
    """Check cluster requirements and fix what's possible."""
    factory = ctx.obj["factory"]

    # Phase 1: diagnose
    info("Checking cluster requirements...")
    checks = factory.doctor.run_checks(on_step=lambda msg: info(msg))

    failed = [c for c in checks if not c.passed]
    if not failed:
        click.echo("")
        for i, check in enumerate(checks, start=1):
            click.echo(f"  [+] {i}. {check.message}")
        click.echo("")
        success(f"All {len(checks)} checks passed. Cluster is ready.")
        return

    # Phase 2: auto-fix what we can
    fixable = [c for c in failed if c.fixable]
    if fixable:
        click.echo("")
        info("Auto-fixing...")
        fixes = factory.doctor.fix_all()
        for fix in fixes:
            marker = "+" if fix.fixed else "!"
            status = "fixed" if fix.fixed else "failed"
            click.echo(f"  [{marker}] {fix.check_name}: {fix.message} ({status})")

        # Re-run after fixes
        click.echo("")
        info("Re-checking...")
        checks = factory.doctor.run_checks()
        failed = [c for c in checks if not c.passed]

    # Phase 3: show results
    click.echo("")
    for i, check in enumerate(checks, start=1):
        marker = "+" if check.passed else "!"
        click.echo(f"  [{marker}] {i}. {check.message}")

    # Phase 4: actionable manual fix instructions
    manual = [c for c in failed if c.fix_hint]
    if manual:
        click.echo("")
        info("Manual steps needed:")
        for check in manual:
            click.echo(f"\n  {check.name}:")
            assert check.fix_hint is not None  # filtered above
            for line in check.fix_hint.splitlines():
                click.echo(f"    {line}")

    click.echo("")
    passed = sum(1 for c in checks if c.passed)
    total = len(checks)
    if all(c.passed for c in checks):
        success(f"All {total} checks passed. Cluster is ready.")
    else:
        click.echo(f"{passed}/{total} checks passed, {total - passed} failed.")
        ctx.exit(1)
