use std::{path::PathBuf, process::Command};

use crate::{Architecture, IntoArgs};

#[derive(Debug)]
pub enum Machine {
    Q35,
}

#[derive(Debug)]
pub enum Cpu {
    Host { enable_kvm: bool },
}

#[derive(Debug)]
pub enum Image {
    Drive(PathBuf),
}

#[derive(Debug, Default)]
pub struct QemuX86_64 {
    pub bios_image: Option<PathBuf>,
    pub boot_slot: Option<char>,
}

impl IntoArgs for Machine {
    fn add_args(&self, command: &mut Command) {
        match self {
            Self::Q35 => {
                command.args(["-M", "q35"]);
            }
        }
    }
}

impl IntoArgs for Cpu {
    fn add_args(&self, command: &mut Command) {
        match self {
            &Self::Host { enable_kvm } => {
                command.args(["-cpu", "host"]);
                if enable_kvm {
                    command.arg("-enable-kvm");
                }
            }
        }
    }
}

impl IntoArgs for Image {
    fn add_args(&self, command: &mut Command) {
        match self {
            Self::Drive(path) => {
                command.args(["-drive", &format!("format=raw,file={}", path.display())]);
            }
        }
    }
}

impl IntoArgs for QemuX86_64 {
    fn add_args(&self, command: &mut Command) {
        if let Some(slot) = self.boot_slot {
            command.arg("-boot");
            command.arg(format!("{}", slot));
        }

        if let Some(bios_image) = self.bios_image.as_ref() {
            command.args([
                "-drive",
                &format!(
                    "format=raw,if=pflash,readonly=on,file={}",
                    bios_image.display()
                ),
            ]);
        }
    }
}

impl Architecture for QemuX86_64 {
    type MachineType = Machine;
    type CpuType = Cpu;
    type ImageType = Image;

    const DEFAULT_COMMAND: &'static str = "qemu-system-x86_64";
}
