import os

from pyinfra import host, inventory
from pyinfra.operations import server, apk, files, openrc
from pyinfra.facts.server import Mounts

from pyinfra_util import get_pass


files.replace(
    name="Enable TCP forwarding via SSH server",
    path="/etc/ssh/sshd_config",
    text="AllowTcpForwarding no",
    replace="AllowTcpForwarding yes",
)
openrc.service(
    name="Restart sshd",
    service="sshd",
    restarted=True,
)

files.replace(
    name="Enable community repository",
    path="/etc/apk/repositories",
    text="#http://dl-cdn.alpinelinux.org/alpine/v3.20/community",
    replace="http://dl-cdn.alpinelinux.org/alpine/v3.20/community",
)
apk.update()
apk.packages(
    packages=["cryptsetup", "vim"]
)

mounts = host.get_fact(Mounts)
if "/var/lib/libvirt" not in mounts:
    decryption_password = get_pass('0x90/ararat/sdb-crypt').strip()
    if decryption_password:
        server.shell(
            name="Decrypt and mount /data",
            commands=[
                f" echo -n '{decryption_password}' | cryptsetup luksOpen --key-file - /dev/sdb1 sdb_crypt || true",
                "mount /dev/mapper/sdb_crypt /var/lib/libvirt",
            ]
        )

apk.packages(
    packages=["libvirt-daemon", "qemu-img", "qemu-system-x86_64", "virt-install"]
)
openrc.service(
    name="Start libvirtd",
    service="libvirtd",
    running=True,
    enabled=False,
)

# add networking: https://wiki.alpinelinux.org/wiki/KVM#Networking
# modprobe tun
# echo "tun" >> /etc/modules-load.d/tun.conf
# cat /etc/modules | grep tun || echo tun >> /etc/modules

# if it doesn't exist, create debian base image (later: and other base images): https://mop.koeln/blog/creating-a-local-debian-vm-using-cloud-init-and-libvirt/#download-the-image
# for every active VM, if no image exists, run virt-install with the chosen base image and their cloud-init.yml file: https://mop.koeln/blog/creating-a-local-debian-vm-using-cloud-init-and-libvirt/#preparing-a-cloud-init-file
debian_image_path = "/var/lib/libvirt/images/debian-12-generic-amd64.qcow2"
files.download(
    name="Download Debian 12 base image",
    src="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2",
    dest=debian_image_path,
)
for vm in inventory.groups.get("debian_vms"):
    if os.path.isfile(f"{vm}/files/cloud-init.yml"):
        files.put(
            name=f"Upload {vm}-cloud-init.yml",
            src=f"{vm}/files/cloud-init.yml",
            dest=f"/root/{vm}-cloud-init.yml",
        )
        #virt-install
    else:
        if vm.data.get("authorized_keys"):
            authorized_keys = "ssh_authorized_keys:\n    - " + "    - ".join(
                [get_pass(f"0x90/ssh_keys/{admin}.pub") for admin in vm.data.get("authorized_keys")]
            )
        else:
            authorized_keys = ""
        files.template(
            name=f"Upload {vm}-cloud-init.yml",
            src="ararat/files/cloud-init.yml.j2",
            dest=f"/root/{vm}-cloud-init.yml",
            ssh_authorized_keys=authorized_keys,
        )
        memory = 1024
        vcpus = 1
        disk_size = 4
        server.shell(
            name=f"virt-install {vm}",
            commands=[
                f"virt-install --name {vm} --disk=size={disk_size},backing_store={debian_image_path} "
                f"--memory {memory} --vcpus {vcpus} --cloud-init user-data=/root/{vm}-cloud-init.yml,disable=on "
                "--network bridge=virbr0 --osinfo=debian12 || true",
            ]
        )
    # for every active VM, make sure an IP is assigned and traffic is passed to it