"""Cloud-init NoCloud ISO generation for per-node static IP configuration (D-03).

Generates ISO files from meta-data and network-config YAML, then ISO-ifies them
using genisoimage or mkisofs. The ISO is attached as a cdrom to each VM so
cloud-init can configure a static IP on first boot without baking per-topology
changes into the base image.
"""

from __future__ import annotations

import logging
import os
import subprocess
import tempfile

logger = logging.getLogger("vmcluster_mcp.cluster.cloud_init")


def generate_cloud_init_iso(
    cluster_name: str,
    node_name: str,
    ip: str,
    mac_address: str,
    gateway_ip: str,
    prefix_len: int,
    output_dir: str,
) -> str:
    """Generate a cloud-init NoCloud ISO for a single node.

    Writes meta-data and network-config YAML into a temp directory, then
    calls genisoimage (or mkisofs as fallback) to produce a cidata ISO.

    Args:
        cluster_name: Used for instance-id.
        node_name: VM hostname and part of the ISO filename.
        ip: Static IP to assign (without prefix).
        mac_address: MAC address to match in network-config v2.
        gateway_ip: Default gateway for the node.
        prefix_len: CIDR prefix length (e.g. 24).
        output_dir: Directory to write the ISO into.

    Returns:
        Absolute path to the generated ISO file.
    """
    iso_path = os.path.join(output_dir, f"{node_name}-cidata.iso")

    meta_data = f"instance-id: {cluster_name}-{node_name}\nlocal-hostname: {node_name}\n"

    network_config = (
        "version: 2\n"
        "ethernets:\n"
        "  id0:\n"
        "    match:\n"
        f"      macaddress: \"{mac_address}\"\n"
        "    addresses:\n"
        f"      - {ip}/{prefix_len}\n"
        "    routes:\n"
        "      - to: default\n"
        f"        via: {gateway_ip}\n"
        "    nameservers:\n"
        "      addresses:\n"
        "        - 8.8.8.8\n"
    )

    with tempfile.TemporaryDirectory() as tmpdir:
        with open(os.path.join(tmpdir, "meta-data"), "w") as f:
            f.write(meta_data)
        with open(os.path.join(tmpdir, "network-config"), "w") as f:
            f.write(network_config)

        _run_iso_generator(iso_path, tmpdir)

    logger.debug("Generated cloud-init ISO for %s/%s at %s", cluster_name, node_name, iso_path)
    return iso_path


def _run_iso_generator(iso_path: str, cwd: str) -> None:
    """Run genisoimage to produce a cidata ISO; fall back to mkisofs."""
    iso_cmd = [
        "genisoimage", "-output", iso_path,
        "-volid", "cidata", "-joliet", "-rock",
        "meta-data", "network-config",
    ]
    try:
        subprocess.run(iso_cmd, cwd=cwd, capture_output=True, check=True)
    except FileNotFoundError:
        logger.debug("genisoimage not found, trying mkisofs")
        fallback_cmd = ["mkisofs"] + iso_cmd[1:]
        subprocess.run(fallback_cmd, cwd=cwd, capture_output=True, check=True)
