"""Cube cluster tools: list, status, cluster_login (server-side via tbot)."""

from __future__ import annotations

import asyncio
import base64
import json
import logging
import os

import yaml

from cube_cloud.teleport.kubeconfig import run_kubectl
from cube_cloud.teleport.tbot_manager import tbot

logger = logging.getLogger(__name__)


async def cube_status(cluster: str | None = None) -> str:
    """Get the status of a Cube node."""
    if not tbot.is_ready:
        return "tbot credentials not ready. Server-side kubectl is not available yet."

    if not cluster:
        return "Error: cluster name is required. Use cube_list to see available clusters."

    output, rc = await run_kubectl(
        ["get", "nodes", "-o", "jsonpath={.items[0].metadata.name}"],
        cluster=cluster,
    )
    if rc != 0:
        return f"Failed to get node: {output}"

    node_name = output.strip()
    if not node_name:
        return "No nodes found. The Cube may not be running."

    output, rc = await run_kubectl(["describe", "node", node_name], cluster=cluster)
    if rc != 0:
        return f"Failed to describe node: {output}"

    return f"Cube Node Status ({cluster} / {node_name}):\n\n{output}"


async def cube_list() -> str:
    """List available Cube clusters from tbot kubeconfigs."""
    if not tbot.is_ready:
        return "tbot credentials not ready. Server-side cluster listing is not available yet."

    clusters = tbot.list_kube_clusters()
    if not clusters:
        return "No Cube clusters configured. tbot kube outputs may still be initializing."

    lines = ["Available Cubes:", "=" * 50]
    for c in clusters:
        lines.append(f"  {c}")

    lines.append("")
    lines.append("Use kubectl_exec with a cluster name to run commands.")
    return "\n".join(lines)


async def cube_cluster_login(cluster: str) -> str:
    """Generate a self-contained kubeconfig for a cluster.

    Reads the tbot-generated kubeconfig to extract cluster info, then runs
    ``tbot kube credentials`` to get fresh client certs.  Returns a
    kubeconfig YAML with embedded certs (no exec plugin — works on any machine).
    """
    if not tbot.is_ready:
        return "Error: Cube credentials are initializing. Try again in a moment."

    if not cluster:
        return "Error: cluster name is required. Use cube_list to see available clusters."

    kubeconfig_path = tbot.get_kubeconfig(cluster)
    if not kubeconfig_path:
        available = tbot.list_kube_clusters()
        avail_str = ", ".join(available) if available else "none"
        return f"Error: Cluster '{cluster}' not found. Available: {avail_str}"

    # 1. Parse the existing kubeconfig for cluster info
    try:
        with open(kubeconfig_path) as f:
            kc = yaml.safe_load(f)
    except Exception as e:
        logger.error("Failed to read kubeconfig for %s: %s", cluster, e)
        return f"Error: Failed to read kubeconfig for '{cluster}'. Contact admin."

    kube_cluster = kc.get("clusters", [{}])[0].get("cluster", {})
    server = kube_cluster.get("server", "")
    ca_data = kube_cluster.get("certificate-authority-data", "")
    tls_server_name = kube_cluster.get("tls-server-name", "")

    if not server:
        return f"Error: kubeconfig for '{cluster}' has no server URL. Contact admin."

    # 2. Run tbot kube credentials to get an ExecCredential JSON
    dest_dir = str(tbot.kube_dir / cluster)
    cmd = ["tbot", "kube", "credentials", f"--destination-dir={dest_dir}"]
    env = {
        "PATH": "/usr/local/bin:/usr/bin:/bin",
        "HOME": "/tmp",
    }
    # Forward AWS credential env vars for IAM join
    for key in (
        "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI",
        "AWS_CONTAINER_CREDENTIALS_FULL_URI",
        "AWS_CONTAINER_AUTHORIZATION_TOKEN",
        "AWS_DEFAULT_REGION",
        "AWS_REGION",
    ):
        val = os.environ.get(key)
        if val:
            env[key] = val

    try:
        proc = await asyncio.create_subprocess_exec(
            *cmd,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
            env=env,
        )
        stdout_data, stderr_data = await asyncio.wait_for(
            proc.communicate(), timeout=30
        )
    except asyncio.TimeoutError:
        return f"Error: Credential generation timed out for '{cluster}'. Try again."
    except FileNotFoundError:
        return "Error: tbot not found on server. Contact admin."

    if proc.returncode != 0:
        stderr_text = stderr_data.decode(errors="replace").strip()
        logger.error("tbot kube credentials failed for %s: %s", cluster, stderr_text)
        return f"Error: Failed to generate credentials for '{cluster}'. Contact admin."

    # 3. Parse ExecCredential JSON
    try:
        exec_cred = json.loads(stdout_data)
    except json.JSONDecodeError:
        logger.error("tbot kube credentials returned invalid JSON for %s", cluster)
        return f"Error: Failed to generate credentials for '{cluster}'. Contact admin."

    status = exec_cred.get("status", {})
    client_cert = status.get("clientCertificateData", "")
    client_key = status.get("clientKeyData", "")
    expires_at = status.get("expirationTimestamp", "")

    if not client_cert or not client_key:
        return f"Error: tbot returned empty credentials for '{cluster}'. Contact admin."

    # 4. Build a self-contained kubeconfig
    kubeconfig_yaml = {
        "apiVersion": "v1",
        "kind": "Config",
        "clusters": [{
            "name": cluster,
            "cluster": {
                "server": server,
                "certificate-authority-data": ca_data,
                **({"tls-server-name": tls_server_name} if tls_server_name else {}),
            },
        }],
        "users": [{
            "name": f"cube-mcp-{cluster}",
            "user": {
                "client-certificate-data": base64.b64encode(client_cert.encode()).decode(),
                "client-key-data": base64.b64encode(client_key.encode()).decode(),
            },
        }],
        "contexts": [{
            "name": cluster,
            "context": {
                "cluster": cluster,
                "user": f"cube-mcp-{cluster}",
            },
        }],
        "current-context": cluster,
    }

    kubeconfig_str = yaml.dump(kubeconfig_yaml, default_flow_style=False)

    # 5. Return JSON with kubeconfig + expiry
    result = {
        "kubeconfig": kubeconfig_str,
        "cluster": cluster,
        "expires_at": expires_at,
    }
    return json.dumps(result)
