#!/usr/bin/env python3
"""Example: Create a fully configured VM with pyvergeos.

This example demonstrates creating a VM with:
- 2 CPU cores and 8GB RAM
- 50GB boot drive on Tier 1 storage
- 100GB data drive on Tier 3 storage
- 1 NIC connected to the External network
- VergeOS installation ISO attached as CD-ROM
- Optional cloud-init configuration for automated provisioning

Usage:
    # Create VM (stopped by default)
    python CreateVM.py

    # Create VM and power it on
    python CreateVM.py --power-on

    # Create VM with custom name
    python CreateVM.py --vm-name my-test-vm

    # Create VM with cloud-init enabled
    python CreateVM.py --cloud-init

    # Create VM and keep it (skip cleanup)
    python CreateVM.py --no-cleanup

Requirements:
- A VergeOS system with:
  - An "External" network
  - Storage tiers 1 and 3 configured
  - The ISO file "verge-io-install-26.0.1.2.iso" uploaded to files
"""

import argparse
import sys
import time
from typing import Any

from pyvergeos import VergeClient
from pyvergeos.exceptions import NotFoundError, VergeError


def create_configured_vm(
    client: VergeClient,
    vm_name: str = "pstest-001",
    power_on: bool = False,
    use_cloud_init: bool = False,
) -> int:
    """Create a fully configured VM.

    Args:
        client: Connected VergeClient instance.
        vm_name: Name for the new VM.
        power_on: Whether to power on the VM after creation.
        use_cloud_init: Whether to enable cloud-init provisioning.

    Returns:
        The created VM's $key.
    """
    print(f"Creating VM: {vm_name}")
    print("-" * 40)

    # Step 1: Create the VM
    cloud_init_desc = " with cloud-init" if use_cloud_init else ""
    print(f"1. Creating VM with 2 CPU cores, 8GB RAM{cloud_init_desc}...")

    # Build VM creation parameters
    vm_params: dict[str, Any] = {
        "name": vm_name,
        "cpu_cores": 2,
        "ram": 8192,  # 8GB in MB
        "description": "Test VM created by pyvergeos example",
        "os_family": "linux",
        "machine_type": "pc-q35-10.0",
    }

    # Add cloud-init configuration if requested
    if use_cloud_init:
        # Basic cloud-init user-data that:
        # - Sets the hostname
        # - Creates a user
        # - Installs a package (qemu-guest-agent for VergeOS integration)
        cloud_init_user_data = f"""#cloud-config
# Cloud-init configuration for {vm_name}
# Generated by pyvergeos CreateVM example

# Set the hostname
hostname: {vm_name}
fqdn: {vm_name}.local
manage_etc_hosts: true

# Create a default user (if supported by the OS image)
users:
  - name: admin
    groups: [sudo, wheel]
    shell: /bin/bash
    sudo: ALL=(ALL) NOPASSWD:ALL
    lock_passwd: false

# Install useful packages
packages:
  - qemu-guest-agent
  - curl

# Run commands on first boot
runcmd:
  - systemctl enable qemu-guest-agent || true
  - systemctl start qemu-guest-agent || true
  - echo "Cloud-init provisioning complete for {vm_name}" > /var/log/cloud-init-done.log

# Final message
final_message: "Cloud-init completed for {vm_name} after $UPTIME seconds"
"""
        vm_params["cloud_init"] = cloud_init_user_data
        print("   Cloud-init: ConfigDrive enabled with user-data")

    vm = client.vms.create(**vm_params)
    print(f"   VM created: key={vm.key}, name={vm.name}")

    # Step 2: Add 50GB boot drive on Tier 1
    print("2. Adding 50GB boot drive on Tier 1...")
    boot_drive = vm.drives.create(
        name="boot_drive",
        size_gb=50,
        interface="virtio-scsi",
        media="disk",
        tier=1,
        description="Boot drive - Tier 1",
    )
    print(f"   Boot drive created: key={boot_drive.key}, size={boot_drive.size_gb}GB")

    # Step 3: Add 100GB data drive on Tier 3
    print("3. Adding 100GB data drive on Tier 3...")
    data_drive = vm.drives.create(
        name="data_drive",
        size_gb=100,
        interface="virtio-scsi",
        media="disk",
        tier=3,
        description="Data drive - Tier 3",
    )
    print(f"   Data drive created: key={data_drive.key}, size={data_drive.size_gb}GB")

    # Step 4: Add CD-ROM with VergeOS ISO
    print("4. Adding CD-ROM with VergeOS installation ISO...")
    try:
        cdrom_drive = vm.drives.create(
            name="cdrom_0",
            interface="ide",
            media="cdrom",
            media_source="verge-io-install-26.0.1.2.iso",
            description="VergeOS installation media",
        )
        print(f"   CD-ROM created: key={cdrom_drive.key}, media={cdrom_drive.get('media_file')}")
    except ValueError as e:
        print(f"   Warning: Could not attach ISO - {e}")
        print("   Continuing without CD-ROM...")

    # Step 5: Add NIC on External network
    print("5. Adding NIC connected to External network...")
    try:
        nic = vm.nics.create(
            name="eth0",
            network="External",
            interface="virtio",
            description="Primary network interface",
        )
        print(f"   NIC created: key={nic.key}, network={nic.network_name}")
    except ValueError as e:
        print(f"   Warning: Could not create NIC on External network - {e}")
        print("   Trying to find available networks...")
        networks = client.networks.list(limit=5)
        if networks:
            net = networks[0]
            print(f"   Using network: {net.name}")
            nic = vm.nics.create(
                name="eth0",
                network=net.key,
                interface="virtio",
                description="Primary network interface",
            )
            print(f"   NIC created: key={nic.key}, network={nic.network_name}")
        else:
            print("   No networks available. VM created without NIC.")

    # Summary
    print()
    print("=" * 40)
    print("VM CREATION COMPLETE")
    print("=" * 40)
    print(f"VM Name:     {vm.name}")
    print(f"VM Key:      {vm.key}")
    print(f"CPU Cores:   {vm.get('cpu_cores')}")
    print(f"RAM:         {vm.get('ram')} MB")

    # List drives
    print("\nDrives:")
    for drive in vm.drives.list():
        print(f"  - {drive.name}: {drive.size_gb}GB ({drive.media_display})")

    # List NICs
    print("\nNICs:")
    for nic in vm.nics.list():
        print(f"  - {nic.name}: {nic.network_name} ({nic.interface_display})")

    # List cloud-init files if any
    cloudinit_files = client.cloudinit_files.list_for_vm(vm.key)
    if cloudinit_files:
        print("\nCloud-Init Files:")
        for cf in cloudinit_files:
            print(f"  - {cf.name}: {cf.filesize} bytes ({cf.render_display})")

    # Power on if requested
    if power_on:
        print("\n6. Powering on VM...")
        vm.power_on()
        print(f"   VM {vm.name} is starting")
        # Wait briefly for status to update
        time.sleep(2)
        vm = client.vms.get(vm.key)  # Refresh
        print(f"   Status: {vm.status}")

    print()
    print(f"Web Console: https://{client.host}/#/vm-console/{vm.key}")

    return vm.key


def cleanup_vm(client: VergeClient, vm_key: int) -> None:
    """Delete a VM and all its resources.

    Args:
        client: Connected VergeClient instance.
        vm_key: The VM $key to delete.
    """
    print()
    print("=" * 40)
    print("CLEANUP")
    print("=" * 40)

    try:
        vm = client.vms.get(vm_key)
        print(f"Deleting VM: {vm.name} (key={vm_key})")

        # Power off if running
        if vm.is_running:
            print("  Powering off VM...")
            vm.power_off(force=True)
            time.sleep(2)

        # Delete the VM
        client.vms.delete(vm_key)
        print("  VM deleted successfully.")

    except NotFoundError:
        print(f"  VM {vm_key} not found (already deleted?).")


def main() -> int:
    """Main entry point."""
    import os

    parser = argparse.ArgumentParser(
        description="Create a fully configured VM with pyvergeos",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  %(prog)s                          # Create VM (stopped)
  %(prog)s --power-on               # Create and start VM
  %(prog)s --vm-name my-vm          # Custom VM name
  %(prog)s --cloud-init             # Create VM with cloud-init
  %(prog)s --no-cleanup             # Keep VM after creation
  %(prog)s --power-on --cloud-init --no-cleanup  # Full example
        """,
    )
    parser.add_argument(
        "--vm-name",
        default="pstest-001",
        help="Name for the VM (default: pstest-001)",
    )
    parser.add_argument(
        "--power-on",
        action="store_true",
        help="Power on the VM after creation",
    )
    parser.add_argument(
        "--no-cleanup",
        action="store_true",
        help="Skip cleanup (keep VM after example completes)",
    )
    parser.add_argument(
        "--cloud-init",
        action="store_true",
        help="Enable cloud-init provisioning with sample user-data",
    )

    args = parser.parse_args()

    print("=" * 40)
    print("pyvergeos CreateVM Example")
    print("=" * 40)
    print()
    print(f"VM Name:    {args.vm_name}")
    print(f"Power On:   {'Yes' if args.power_on else 'No'}")
    print(f"Cloud-Init: {'Yes' if args.cloud_init else 'No'}")
    print(f"Cleanup:    {'No' if args.no_cleanup else 'Yes'}")
    print()

    # Configuration from environment variables
    host = os.environ.get("VERGE_HOST", "")
    if not host:
        print("Error: VERGE_HOST environment variable not set")
        return 1

    # Connect to VergeOS
    print(f"Connecting to {host}...")
    try:
        with VergeClient.from_env() as client:
            print(f"Connected! VergeOS version: {client.version}")
            print()

            # Check if VM already exists
            try:
                existing = client.vms.get(name=args.vm_name)
                print(f"VM '{args.vm_name}' already exists (key={existing.key}).")
                print("Cleaning up existing VM first...")
                cleanup_vm(client, existing.key)
                print()
            except NotFoundError:
                pass  # VM doesn't exist, proceed with creation

            # Create the VM
            vm_key = create_configured_vm(
                client,
                args.vm_name,
                power_on=args.power_on,
                use_cloud_init=args.cloud_init,
            )

            # Clean up unless --no-cleanup specified
            if not args.no_cleanup:
                print("\nWaiting 5 seconds before cleanup...")
                time.sleep(5)
                cleanup_vm(client, vm_key)
            else:
                print()
                print("=" * 40)
                print("SKIPPING CLEANUP")
                print("=" * 40)
                print(f"VM '{args.vm_name}' (key={vm_key}) left for inspection.")
                print("Delete manually when done.")

            print()
            print("Example completed successfully!")
            return 0

    except VergeError as e:
        print(f"Error: {e}")
        return 1


if __name__ == "__main__":
    sys.exit(main())
