"""``ilum connect`` command."""

from __future__ import annotations

import typer

import ilum.cli.output as output_mod
from ilum.config.manager import ConfigManager
from ilum.config.paths import IlumPaths
from ilum.core.helm import HelmClient
from ilum.core.kubernetes import KubeClient
from ilum.core.modules import ModuleResolver
from ilum.core.release import ReleaseInfo, ReleaseManager
from ilum.core.safety import make_snapshot, save_snapshot
from ilum.errors import IlumError
from ilum.wizard.deps import ensure_tools


def _build_manager(
    context: str,
    namespace: str,
) -> ReleaseManager:
    paths = IlumPaths.default()
    paths.ensure_dirs()
    return ReleaseManager(
        helm=HelmClient(kubecontext=context, namespace=namespace),
        k8s=KubeClient(kubecontext=context),
        resolver=ModuleResolver(),
        config_mgr=ConfigManager(paths),
        paths=paths,
    )


def connect(
    release: str | None = typer.Option(
        None,
        "--release",
        "-r",
        help="Helm release name (skips auto-detection).",
    ),
    namespace: str | None = typer.Option(
        None,
        "--namespace",
        "-n",
        help="Kubernetes namespace (scans all if omitted).",
    ),
    context: str | None = typer.Option(
        None,
        "--context",
        help="Kubernetes context.",
    ),
    profile: str = typer.Option(
        "default",
        "--profile",
        "-p",
        help="Profile name to create or update.",
    ),
    yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompts."),
    no_switch: bool = typer.Option(
        False, "--no-switch", help="Don't switch active profile after connecting."
    ),
) -> None:
    """Connect the CLI to an existing Ilum installation."""
    console = output_mod.console

    try:
        ensure_tools(["helm"], console, interactive=not yes)
        # When release is specified with namespace, go direct
        # When release is specified without namespace, scan all namespaces
        # When neither is specified, scan all namespaces
        scan_namespace = namespace or ""
        mgr = _build_manager(context or "", scan_namespace)

        if release and namespace:
            # Direct mode: validate the specific release
            try:
                info = mgr.get_release_info(release)
            except IlumError as exc:
                console.error(f"Release '{release}' not found in namespace '{namespace}'.")
                console.info("Run 'ilum connect' without --release to scan for available releases.")
                raise typer.Exit(code=1) from exc

            # Validate it's an Ilum chart
            if not _is_ilum_chart(info.chart):
                console.error(f"Release '{release}' is not an Ilum chart (chart: {info.chart}).")
                raise typer.Exit(code=1)
        else:
            # Scan mode: find Ilum releases
            with console.status_spinner("Scanning for Ilum releases..."):
                releases = mgr.scan_releases(namespace=scan_namespace)

            if not releases:
                ctx_label = f" in context '{context}'" if context else ""
                console.error(f"No Ilum releases found{ctx_label}.")
                console.info(
                    "Check your kubeconfig context with 'kubectl config current-context', "
                    "or use 'ilum install' to create a new installation."
                )
                raise typer.Exit(code=1)

            if len(releases) == 1:
                info = releases[0]
                if not yes:
                    _show_release_info(console, info)
                    if not console.confirm(
                        f"Connect this release to profile '{profile}'?", default=True
                    ):
                        console.info("Aborted.")
                        raise typer.Exit()
            else:
                # Multiple releases — show table and let user pick
                _show_releases_table(console, releases)
                if yes:
                    info = releases[0]
                    console.info(f"Auto-selected first release: {info.name}")
                else:
                    choice = console.prompt_text(f"Select release [1-{len(releases)}]")
                    try:
                        idx = int(choice) - 1
                        if idx < 0 or idx >= len(releases):
                            raise ValueError
                        info = releases[idx]
                    except ValueError as exc:
                        console.error("Invalid selection.")
                        raise typer.Exit(code=1) from exc

            # Update namespace/release from discovered info
            release = info.name
            namespace = info.namespace
            # Rebuild manager with the correct namespace
            mgr = _build_manager(context or "", namespace)

        # Check for profile already connected
        config = mgr.config_mgr.load()
        existing_profile = config.profiles.get(profile)
        if (
            existing_profile
            and existing_profile.release_name
            and existing_profile.release_name != release
            and not yes
        ):
            console.warning(
                f"Profile '{profile}' is already connected to release "
                f"'{existing_profile.release_name}' in namespace "
                f"'{existing_profile.cluster.namespace}'."
            )
            if not console.confirm("Overwrite?"):
                console.info("Aborted.")
                raise typer.Exit()

        # Detect enabled modules from live values
        try:
            computed_values = mgr.fetch_computed_values(release)
            live_modules = mgr.resolver.detect_enabled_modules(computed_values)
            user_values = mgr.fetch_live_values(release)
        except IlumError:
            computed_values = {}
            user_values = {}
            live_modules = []

        # Get chart version from release info
        try:
            info = mgr.get_release_info(release)
            chart_version = info.chart_version
            release_status = info.status
        except IlumError:
            chart_version = ""
            release_status = "unknown"

        # Update profile
        from ilum.config.models import ClusterConfig, ProfileConfig

        if profile not in config.profiles:
            config.profiles[profile] = ProfileConfig(name=profile)

        p = config.profiles[profile]
        p.release_name = release
        p.cluster = ClusterConfig(
            kubecontext=context or p.cluster.kubecontext,
            namespace=namespace or p.cluster.namespace,
            chart_version=chart_version,
        )
        p.enabled_modules = sorted(live_modules)
        if not no_switch:
            config.active_profile = profile
        mgr.config_mgr.save(config)

        console.success(
            f"Profile '{profile}' updated with release '{release}' in namespace '{namespace}'."
        )
        console.success(f"{len(live_modules)} modules synced to config.")

        # Save values snapshot for drift detection
        if user_values:
            snapshot = make_snapshot(
                release=release,
                namespace=namespace,
                chart_version=chart_version,
                values=user_values,
                operation="connect",
            )
            save_snapshot(snapshot, mgr.paths.state_dir)
            console.success("Values snapshot saved (drift detection enabled).")

        # Warn about stuck releases
        if release_status in ("pending-install", "pending-upgrade", "pending-rollback"):
            console.warning(
                f"Release '{release}' is in '{release_status}' state. "
                "Run 'ilum upgrade --force-rollback' to recover."
            )

        # Next steps
        console.info("")
        console.info("Next steps:")
        console.info("  ilum status          Show release status")
        console.info("  ilum upgrade         Upgrade to a newer version")
        console.info("  ilum module enable   Enable additional modules")

    except IlumError as exc:
        console.handle_error(exc)
        raise typer.Exit(code=1) from exc


def _is_ilum_chart(chart_name: str) -> bool:
    """Return True if the chart name looks like an Ilum chart."""
    return chart_name == "ilum" or chart_name.startswith("ilum-")


def _show_release_info(console: output_mod.IlumConsole, info: ReleaseInfo) -> None:
    """Show a single release's info."""
    status_color = "green" if info.status == "deployed" else "yellow"
    console.info("Found 1 Ilum release:")
    lines = [
        f"  Release:   {info.name}",
        f"  Namespace: {info.namespace}",
        f"  Version:   {info.chart_version}",
        f"  Status:    [{status_color}]{info.status}[/{status_color}]",
    ]
    for line in lines:
        console.info(line)


def _show_releases_table(console: output_mod.IlumConsole, releases: list) -> None:
    """Show multiple releases in a table."""
    rows = []
    for i, info in enumerate(releases, 1):
        rows.append(
            [
                str(i),
                info.name,
                info.namespace,
                info.chart_version,
                info.status,
            ]
        )
    console.table(
        "Found Ilum Releases",
        ["#", "Release", "Namespace", "Version", "Status"],
        rows,
    )
