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

use crate::{Architecture, IntoArgs};

#[derive(Debug)]
pub enum Cpu {
    Rv64,
}

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

#[derive(Debug)]
pub struct QemuRiscv64;

#[derive(Debug)]
pub enum Image {
    OpenSBI {
        bios: PathBuf,
        kernel: PathBuf,
        initrd: PathBuf,
    },
}

impl IntoArgs for Machine {
    fn add_args(&self, command: &mut Command) {
        command.arg("-M");
        match self {
            Self::Virt => command.arg("virt"),
        };
    }
}

impl IntoArgs for Cpu {
    fn add_args(&self, command: &mut Command) {
        command.arg("-cpu");
        match self {
            Self::Rv64 => command.arg("rv64,a=true,zicsr=true,zifencei=true"),
        };
    }
}

impl IntoArgs for Image {
    fn add_args(&self, command: &mut Command) {
        match self {
            Self::OpenSBI {
                bios,
                kernel,
                initrd,
            } => {
                command.arg("-kernel");
                command.arg(kernel);
                command.arg("-initrd");
                command.arg(initrd);
                command.arg("-bios");
                command.arg(bios);
            }
        }
    }
}

impl Architecture for QemuRiscv64 {
    type CpuType = Cpu;
    type ImageType = Image;
    type MachineType = Machine;
    const DEFAULT_COMMAND: &'static str = "qemu-system-riscv64";
}

impl IntoArgs for QemuRiscv64 {
    fn add_args(&self, command: &mut Command) {
        let _ = command;
    }
}
