//! Processor type definitions.

use serde::{Deserialize, Serialize};

/// All supported processor types.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ProcessorType {
    /// Central Processing Unit.
    Cpu(CpuVariant),
    /// Graphics Processing Unit.
    Gpu(GpuVariant),
    /// Tensor Processing Unit (Google).
    Tpu(TpuVersion),
    /// Neural Processing Unit (various vendors).
    Npu(NpuVariant),
    /// Language Processing Unit (Groq).
    Lpu,
    /// Field Programmable Gate Array.
    Fpga(FpgaVendor),
    /// Digital Signal Processor.
    Dsp(DspVariant),
    /// WebGPU (browser).
    WebGpu,
    /// WebAssembly runtime.
    Wasm,
    /// Custom/Unknown accelerator.
    Custom {
        vendor: String,
        model: String,
    },
}

impl Default for ProcessorType {
    fn default() -> Self {
        ProcessorType::Cpu(CpuVariant::default())
    }
}

/// CPU architecture variants.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum CpuVariant {
    /// x86-64 architecture.
    X86_64 { avx: AvxSupport },
    /// ARM 64-bit architecture.
    Arm64 { sve: bool },
    /// RISC-V architecture.
    RiscV { vector: bool },
}

impl Default for CpuVariant {
    fn default() -> Self {
        CpuVariant::X86_64 {
            avx: AvxSupport::Avx2,
        }
    }
}

/// AVX instruction set support levels.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub enum AvxSupport {
    /// No AVX.
    None,
    /// AVX (Sandy Bridge+).
    Avx,
    /// AVX2 (Haswell+).
    Avx2,
    /// AVX-512 (Skylake-X+).
    Avx512,
    /// AVX10 (future).
    Avx10,
}

/// GPU vendor variants.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum GpuVariant {
    /// NVIDIA CUDA GPU.
    NvidiaCuda {
        /// Compute capability (major, minor).
        compute_capability: (u8, u8),
    },
    /// AMD ROCm GPU.
    AmdRocm {
        /// GFX version (e.g., 1100 for RDNA3).
        gfx_version: u32,
    },
    /// Intel OneAPI GPU.
    IntelOneApi,
    /// Apple Metal GPU.
    AppleMetal,
    /// Qualcomm Adreno GPU.
    QualcommAdreno {
        /// Adreno model number.
        model: u32,
    },
    /// ARM Mali GPU.
    ArmMali {
        /// Mali generation (e.g., G710).
        model: u32,
    },
    /// IMG PowerVR GPU.
    ImgPowerVr,
}

/// Google TPU versions.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum TpuVersion {
    /// TPU v2.
    V2,
    /// TPU v3.
    V3,
    /// TPU v4.
    V4,
    /// TPU v4i (inference).
    V4i,
    /// TPU v5e (efficiency).
    V5e,
    /// TPU v5p (performance).
    V5p,
    /// Edge TPU.
    Edge,
}

/// NPU (Neural Processing Unit) variants.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum NpuVariant {
    /// Apple Neural Engine.
    AppleNeuralEngine {
        /// Number of cores.
        cores: u32,
    },
    /// Qualcomm Hexagon DSP/NPU.
    QualcommHexagon {
        /// Version number.
        version: u32,
    },
    /// Intel VPU (Movidius).
    IntelVpu,
    /// Huawei Ascend.
    HuaweiAscend {
        /// Model (310, 910, etc.).
        model: u32,
    },
    /// Google Edge TPU.
    GoogleEdgeTpu,
    /// Samsung NPU.
    SamsungNpu,
    /// MediaTek APU.
    MediaTekApu {
        /// Version.
        version: u32,
    },
    /// Custom NPU.
    Custom {
        /// TOPS (Tera Operations Per Second).
        tops: u32,
    },
}

/// FPGA vendors.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum FpgaVendor {
    /// Xilinx (AMD).
    Xilinx,
    /// Intel (Altera).
    Intel,
    /// Lattice.
    Lattice,
    /// Microchip.
    Microchip,
}

/// DSP (Digital Signal Processor) variants.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum DspVariant {
    /// Texas Instruments DSP.
    TexasInstruments,
    /// Analog Devices DSP.
    AnalogDevices,
    /// Qualcomm Hexagon DSP.
    QualcommHexagon,
    /// Custom DSP.
    Custom,
}

impl ProcessorType {
    /// Returns whether this processor type supports CUDA.
    pub fn supports_cuda(&self) -> bool {
        matches!(self, ProcessorType::Gpu(GpuVariant::NvidiaCuda { .. }))
    }

    /// Returns whether this processor type supports ROCm.
    pub fn supports_rocm(&self) -> bool {
        matches!(self, ProcessorType::Gpu(GpuVariant::AmdRocm { .. }))
    }

    /// Returns whether this processor type supports Metal.
    pub fn supports_metal(&self) -> bool {
        matches!(self, ProcessorType::Gpu(GpuVariant::AppleMetal))
    }

    /// Returns whether this processor type is a GPU.
    pub fn is_gpu(&self) -> bool {
        matches!(self, ProcessorType::Gpu(_))
    }

    /// Returns whether this processor type is a CPU.
    pub fn is_cpu(&self) -> bool {
        matches!(self, ProcessorType::Cpu(_))
    }

    /// Returns whether this processor type is suitable for parallel workloads.
    pub fn is_parallel(&self) -> bool {
        matches!(
            self,
            ProcessorType::Gpu(_) | ProcessorType::Tpu(_) | ProcessorType::Fpga(_)
        )
    }

    /// Returns whether this processor type is suitable for sequential workloads.
    pub fn is_sequential(&self) -> bool {
        matches!(self, ProcessorType::Cpu(_) | ProcessorType::Lpu)
    }

    /// Returns whether this processor type is power-efficient.
    pub fn is_low_power(&self) -> bool {
        matches!(
            self,
            ProcessorType::Npu(_) | ProcessorType::Tpu(TpuVersion::Edge) | ProcessorType::Wasm
        )
    }

    /// Returns the typical power consumption tier.
    pub fn power_tier(&self) -> PowerTier {
        match self {
            ProcessorType::Npu(_) | ProcessorType::Wasm => PowerTier::UltraLow,
            ProcessorType::Cpu(CpuVariant::Arm64 { .. }) => PowerTier::Low,
            ProcessorType::Cpu(_) => PowerTier::Medium,
            ProcessorType::Gpu(GpuVariant::AppleMetal) => PowerTier::Medium,
            ProcessorType::Gpu(GpuVariant::NvidiaCuda { compute_capability })
                if compute_capability.0 >= 8 =>
            {
                PowerTier::High
            }
            ProcessorType::Gpu(_) => PowerTier::Medium,
            ProcessorType::Tpu(TpuVersion::Edge) => PowerTier::UltraLow,
            ProcessorType::Tpu(_) => PowerTier::High,
            ProcessorType::Lpu => PowerTier::Medium,
            ProcessorType::Fpga(_) => PowerTier::Medium,
            ProcessorType::Dsp(_) => PowerTier::Low,
            ProcessorType::WebGpu => PowerTier::Low,
            ProcessorType::Custom { .. } => PowerTier::Medium,
        }
    }
}

/// Power consumption tiers.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum PowerTier {
    /// < 5W (mobile, IoT).
    UltraLow,
    /// 5-30W (laptop, tablet).
    Low,
    /// 30-150W (desktop, workstation).
    Medium,
    /// > 150W (server, data center).
    High,
}

/// Device class for routing decisions.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum DeviceClass {
    /// Data center equipment.
    DataCenter,
    /// Desktop/workstation.
    Desktop,
    /// Laptop.
    Laptop,
    /// Mobile phone.
    Mobile,
    /// Tablet.
    Tablet,
    /// IoT device.
    IoT,
    /// Browser (WebGPU/WASM).
    Browser,
    /// Edge server.
    Edge,
}

impl DeviceClass {
    /// Returns typical available compute hours per day.
    pub fn typical_availability_hours(&self) -> f32 {
        match self {
            DeviceClass::DataCenter => 24.0,
            DeviceClass::Desktop => 8.0,
            DeviceClass::Laptop => 6.0,
            DeviceClass::Mobile => 4.0,
            DeviceClass::Tablet => 4.0,
            DeviceClass::IoT => 24.0,
            DeviceClass::Browser => 2.0,
            DeviceClass::Edge => 24.0,
        }
    }

    /// Returns reliability score (0-100).
    pub fn reliability_score(&self) -> u32 {
        match self {
            DeviceClass::DataCenter => 99,
            DeviceClass::Edge => 95,
            DeviceClass::Desktop => 80,
            DeviceClass::Laptop => 60,
            DeviceClass::Mobile => 40,
            DeviceClass::Tablet => 50,
            DeviceClass::IoT => 70,
            DeviceClass::Browser => 30,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_processor_type_properties() {
        let nvidia = ProcessorType::Gpu(GpuVariant::NvidiaCuda {
            compute_capability: (9, 0),
        });
        assert!(nvidia.supports_cuda());
        assert!(nvidia.is_gpu());
        assert!(nvidia.is_parallel());

        let cpu = ProcessorType::Cpu(CpuVariant::X86_64 {
            avx: AvxSupport::Avx512,
        });
        assert!(cpu.is_cpu());
        assert!(cpu.is_sequential());

        let lpu = ProcessorType::Lpu;
        assert!(lpu.is_sequential());

        let npu = ProcessorType::Npu(NpuVariant::AppleNeuralEngine { cores: 16 });
        assert!(npu.is_low_power());
    }

    #[test]
    fn test_power_tiers() {
        let h100 = ProcessorType::Gpu(GpuVariant::NvidiaCuda {
            compute_capability: (9, 0),
        });
        assert_eq!(h100.power_tier(), PowerTier::High);

        let npu = ProcessorType::Npu(NpuVariant::AppleNeuralEngine { cores: 16 });
        assert_eq!(npu.power_tier(), PowerTier::UltraLow);

        let arm = ProcessorType::Cpu(CpuVariant::Arm64 { sve: false });
        assert_eq!(arm.power_tier(), PowerTier::Low);
    }

    #[test]
    fn test_device_class() {
        assert_eq!(DeviceClass::DataCenter.typical_availability_hours(), 24.0);
        assert_eq!(DeviceClass::Mobile.typical_availability_hours(), 4.0);
        assert_eq!(DeviceClass::DataCenter.reliability_score(), 99);
        assert_eq!(DeviceClass::Browser.reliability_score(), 30);
    }
}
