// Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: MIT

#![allow(dead_code)]

use lazy_static::lazy_static;
use raw_cpuid::CpuId;
use raw_cpuid::CpuIdReaderNative;

use crate::arch::x86_64::amd_virt::amd_v_supported;
use crate::arch::x86_64::intel_virt::intel_vt_supported;

lazy_static! {
    pub static ref CPUID: CpuId<CpuIdReaderNative> = CpuId::new();
}

#[derive(Debug)]
pub enum VirtualizationProvider {
    AmdV,
    IntelVTx,
    None,
}

#[derive(PartialEq, Eq)]
#[allow(clippy::upper_case_acronyms)]
pub enum ProcessorVendor {
    AMD,
    Intel,
    Via,
    Transmeta,
    Cyrix,
    Centaur,
    Nexgen,
    UMC,
    SiS,
    NSC,
    Rise,
    Vortex,
    AO486,
    Zaoxin,
    Hygon,
    Elbrus,
    QEMU,
    KVM,
    VMware,
    VirtualBox,
    Xen,
    HyperV,
    Parallels,
    QNX,
}

impl TryFrom<&str> for ProcessorVendor {
    type Error = ();
    fn try_from(from: &str) -> Result<Self, Self::Error> {
        match from {
            "AuthenticAMD" | "AMDisbetter!" => Ok(Self::AMD),
            // "GenuineIotel" is a legit string found in some mildly defective Intel CPUs
            "GenuineIntel" | "GenuineIotel" => Ok(Self::Intel),
            "VIA VIA VIA " => Ok(Self::Via),
            "GenuineTMx86" | "TransmetaCPU" => Ok(Self::Transmeta),
            "CyrixInstead" => Ok(Self::Cyrix),
            "CentaurHauls" => Ok(Self::Centaur),
            "NexGenDriven" => Ok(Self::Nexgen),
            "UMC UMC UMC " => Ok(Self::UMC),
            "SiS SiS SiS " => Ok(Self::SiS),
            "Geode by NSC" => Ok(Self::NSC),
            "RiseRiseRise" => Ok(Self::Rise),
            "Vortex86 SoC" => Ok(Self::Vortex),
            "MiSTer AO486" | "GenuineAO486" => Ok(Self::AO486),
            "  Shanghai  " => Ok(Self::Zaoxin),
            "HygonGenuine" => Ok(Self::Hygon),
            "E2K MACHINE " => Ok(Self::Elbrus),
            "TCGTCGTCGTCG" => Ok(Self::QEMU),
            " KVMKVMKVM  " => Ok(Self::KVM),
            "VMwareVMware" => Ok(Self::VMware),
            "VBoxVBoxVBox" => Ok(Self::VirtualBox),
            "XenVMMXenVMM" => Ok(Self::Xen),
            "Microsoft Hv" => Ok(Self::HyperV),
            // " lrpepyh vr " is a legit string found in some implementations of the
            // Parallels hypervisor due to an endianness mismatch
            " prl hyperv " | " lrpepyh vr " => Ok(Self::Parallels),
            " QNXQVMBSQG " => Ok(Self::QNX),
            _ => Err(()),
        }
    }
}

impl ProcessorVendor {
    pub fn is_hypervisor(&self) -> bool {
        matches!(
            self,
            Self::QEMU
                | Self::KVM
                | Self::VMware
                | Self::VirtualBox
                | Self::HyperV
                | Self::Parallels
                | Self::QNX
        )
    }
    pub fn try_get_current() -> Result<Self, ()> {
        if let Some(brand_string) = CPUID.get_vendor_info() {
            Self::try_from(brand_string.as_str())
        } else {
            Err(())
        }
    }
}

pub fn virt_supported() -> VirtualizationProvider {
    match ProcessorVendor::try_get_current() {
        Err(_) => VirtualizationProvider::None,
        Ok(ProcessorVendor::Intel) => {
            if intel_vt_supported() {
                VirtualizationProvider::IntelVTx
            } else {
                VirtualizationProvider::None
            }
        }
        Ok(ProcessorVendor::AMD) => {
            if amd_v_supported() {
                VirtualizationProvider::AmdV
            } else {
                VirtualizationProvider::None
            }
        }
        _ => VirtualizationProvider::None,
    }
}
