"""cube_cluster_login — fetch kubeconfig from cube-cloud and merge into ~/.kube/config."""

from __future__ import annotations

import json
import logging
import os
from pathlib import Path

import yaml

from cube_agent.remote.client import CloudClient, CloudClientError

logger = logging.getLogger(__name__)

DEFAULT_KUBECONFIG = Path.home() / ".kube" / "config"


def _merge_kubeconfig(new_kc: dict, target: Path) -> None:
    """Merge *new_kc* into the kubeconfig at *target*.

    For each section (clusters, users, contexts): find by name and overwrite,
    or append if not present.  Sets ``current-context`` to the new cluster.
    Writes the file with 0o600 permissions.
    """
    if target.exists():
        existing = yaml.safe_load(target.read_text()) or {}
    else:
        existing = {}

    # Ensure skeleton structure
    existing.setdefault("apiVersion", "v1")
    existing.setdefault("kind", "Config")
    existing.setdefault("clusters", [])
    existing.setdefault("users", [])
    existing.setdefault("contexts", [])

    for section in ("clusters", "users", "contexts"):
        for new_entry in new_kc.get(section, []):
            name = new_entry.get("name")
            # Find and replace existing entry with same name, or append
            found = False
            for i, entry in enumerate(existing[section]):
                if entry.get("name") == name:
                    existing[section][i] = new_entry
                    found = True
                    break
            if not found:
                existing[section].append(new_entry)

    existing["current-context"] = new_kc.get("current-context", "")

    # Ensure parent directory exists
    target.parent.mkdir(parents=True, exist_ok=True)
    target.write_text(yaml.dump(existing, default_flow_style=False))
    os.chmod(target, 0o600)


async def kube_login(cluster: str) -> str:
    """Fetch a kubeconfig for *cluster* from cube-cloud and merge into ~/.kube/config.

    Returns a user-friendly message with usage instructions.
    """
    if not cluster:
        return "Error: cluster name is required. Use cube_list to see available clusters."

    try:
        async with CloudClient() as cloud:
            raw = await cloud.call_tool("cube_cluster_login", {"cluster": cluster})
    except CloudClientError as e:
        msg = str(e)
        if "401" in msg or "Authentication" in msg.lower():
            return "Authentication failed. Run `agent_login` with a valid API key."
        return f"Could not reach cube-cloud. Check network connectivity.\nDetails: {msg}"

    # If the server returned a plain error string, pass it through
    if raw.startswith("Error:"):
        return raw

    # Parse the JSON envelope
    try:
        data = json.loads(raw)
    except json.JSONDecodeError:
        return f"Error: Unexpected response from cube-cloud:\n{raw[:500]}"

    kubeconfig_yaml = data.get("kubeconfig", "")
    expires_at = data.get("expires_at", "unknown")
    cluster_name = data.get("cluster", cluster)

    if not kubeconfig_yaml:
        return "Error: cube-cloud returned an empty kubeconfig."

    # Parse the new kubeconfig and merge into ~/.kube/config
    new_kc = yaml.safe_load(kubeconfig_yaml)
    _merge_kubeconfig(new_kc, DEFAULT_KUBECONFIG)

    lines = [
        f"Kubeconfig merged into {DEFAULT_KUBECONFIG}",
        f"Current context set to: {cluster_name}",
        "",
        "Try it:",
        "  kubectl get namespaces",
        "",
        f"Credentials expire at: {expires_at}",
        "Run cube_cluster_login again to refresh when expired.",
    ]
    return "\n".join(lines)
