"""CLI commands for exporting artifacts to remote hosts."""
from __future__ import annotations

from pathlib import Path

import click

from k4s.cli.errors import exit_with_error
from k4s.cli.state import CliState
from k4s.cli.verbosity import apply_command_ui_overrides
from k4s.core.executor import Executor


@click.group()
def export():
    """Export artifacts to remote hosts."""
    pass


@export.command("kubeconfig")
@click.option(
    "--from",
    "from_context",
    required=True,
    help="VM context name of the RKE2 control-plane node to read the kubeconfig from.",
)
@click.option(
    "--to",
    "to_context",
    required=True,
    help="VM context name of the target machine to copy the kubeconfig to.",
)
@click.option(
    "--path",
    "export_path",
    default=None,
    help=(
        "Destination path on the target machine. "
        "Defaults to /home/<username>/.kube/config (or /root/.kube/config for root)."
    ),
)
@click.option(
    "--control-plane-ip",
    default=None,
    help=(
        "Override the control-plane IP written into the kubeconfig. "
        "Defaults to the host of the --from context."
    ),
)
@click.option("-q", "--quiet", is_flag=True, help="Only print final results and errors.")
@click.option("-v", "--verbose", count=True, help="Increase verbosity (-v logs, -vv debug).")
@click.pass_context
def kubeconfig(ctx, from_context, to_context, export_path, control_plane_ip, quiet, verbose):
    """Copy the RKE2 kubeconfig from a control-plane node to another VM.

    The kubeconfig is written to the target machine and KUBECONFIG is persisted
    in the target user's shell profile (~/.bashrc and ~/.profile).

    Example:

    \b
      k4s export kubeconfig --from rke2-cp --to dataiku-vm
    """
    state: CliState = ctx.obj["state"]
    apply_command_ui_overrides(ctx, state, quiet=quiet, verbose=verbose)
    ui = state.ui

    try:
        # Resolve source (control-plane) context.
        try:
            src = state.contexts.resolve(from_context)
        except KeyError:
            raise ValueError(
                f"Context '{from_context}' not found.\n"
                f"  List contexts: k4s context list\n"
                f"  Add context:   k4s context add {from_context} ..."
            )

        # Resolve destination context.
        try:
            dst = state.contexts.resolve(to_context)
        except KeyError:
            raise ValueError(
                f"Context '{to_context}' not found.\n"
                f"  List contexts: k4s context list\n"
                f"  Add context:   k4s context add {to_context} ..."
            )

        # Determine destination path and whether it is kubectl's default location.
        dst_user = dst.username or "root"
        kubectl_default = "/root/.kube/config" if dst_user == "root" else f"/home/{dst_user}/.kube/config"

        if not export_path:
            export_path = kubectl_default

        is_default_path = export_path == kubectl_default

        cp_host = control_plane_ip or src.host

        with ui.step(f"Read kubeconfig from {from_context} ({src.host})"):
            src_sudo = (src.username or "").lower() not in {"root"}
            with Executor(src.to_server_config()) as src_ex:
                content = src_ex.read_remote_file_content(
                    "/etc/rancher/rke2/rke2.yaml", use_sudo=src_sudo
                )

        # Replace the loopback address so kubectl can reach the cluster remotely.
        content = content.replace("127.0.0.1", cp_host)

        kube_dir = str(Path(export_path).parent)
        dst_sudo = (dst.username or "").lower() not in {"root"}
        _sudo = "sudo -n " if dst_sudo else ""

        with ui.step(f"Write kubeconfig to {to_context} ({dst.host}:{export_path})"):
            with Executor(dst.to_server_config()) as dst_ex:
                dst_ex.execute(f"{_sudo}mkdir -p {kube_dir}", use_sudo=False)
                dst_ex.execute(f"{_sudo}chmod 700 {kube_dir}", use_sudo=False)
                if dst_sudo:
                    dst_ex.execute(f"sudo -n chown {dst_user}:{dst_user} {kube_dir}", use_sudo=False)

                rc, out, err = dst_ex.execute(
                    f"{_sudo}tee {export_path}",
                    use_sudo=False,
                    stdin_data=content,
                )
                if rc != 0:
                    raise RuntimeError(
                        f"Failed to write kubeconfig to {dst.host}:{export_path}: {err or out}"
                    )

                dst_ex.execute(f"{_sudo}chmod 600 {export_path}", use_sudo=False)
                if dst_sudo:
                    dst_ex.execute(f"sudo -n chown {dst_user}:{dst_user} {export_path}", use_sudo=False)

        if not is_default_path:
            # Path is non-default: kubectl won't find it automatically, so persist
            # KUBECONFIG in the user's shell profile.
            with ui.step("Persist KUBECONFIG in shell profile"):
                export_line = f"export KUBECONFIG={export_path}"
                with Executor(dst.to_server_config()) as dst_ex:
                    for rc_file in ("~/.bashrc", "~/.profile"):
                        dst_ex.execute(
                            f"grep -qF '{export_line}' {rc_file} 2>/dev/null "
                            f"|| echo '{export_line}' >> {rc_file}",
                            use_sudo=False,
                        )

        state.history.append(
            action="export-kubeconfig",
            product="cluster",
            context=src.name,
            host=src.host,
            params={"from": from_context, "to": to_context, "path": export_path},
        )
        ui.success(f"Kubeconfig exported to {dst.host}:{export_path}")
        if is_default_path:
            ui.info("  kubectl will find this config automatically (default location).")
        else:
            ui.info(f"  KUBECONFIG={export_path} added to shell profile on {dst.host}.")
            ui.info(f"  Run 'source ~/.bashrc' in your current session on {dst.host} to activate it.")
        ui.info(f"  Run 'kubectl get nodes' on {dst.host} to verify cluster access.")

    except Exception as e:
        exit_with_error(ctx, ui, e, code=1)
