//! Fallback implementations for CUDA types when CUDA is not available
//!
//! This module provides stub implementations of CUDA types that return appropriate
//! errors or no-op behaviors when CUDA is not available on the system.

use crate::backend::{
    Backend, BackendCapabilities, BackendCore, BackendDeviceManager, BackendExecutor,
    BackendLifecycle, BackendOperations, BackendOps, BackendResourceManager, BackendType,
    ExtendedCapabilities, OperationsBundle, PerformanceHints,
};
use crate::error::BackendError;
use crate::{
    BackendResult, Buffer, BufferDescriptor, Device, Kernel, KernelDescriptor, MemoryManager,
    Profiler,
};
use torsh_core::{device::DeviceType, error::TorshError};

/// Fallback CUDA error type
#[derive(Debug, Clone)]
pub enum CudaError {
    RuntimeError(String),
    InitializationFailed(String),
    InvalidDevice(String),
    OutOfMemory(String),
    InvalidValue(String),
    UnknownError(String),
}

impl std::fmt::Display for CudaError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            CudaError::RuntimeError(message) => write!(f, "CUDA runtime error: {}", message),
            CudaError::InitializationFailed(msg) => {
                write!(f, "CUDA initialization failed: {}", msg)
            }
            CudaError::InvalidDevice(msg) => write!(f, "Invalid CUDA device: {}", msg),
            CudaError::OutOfMemory(msg) => write!(f, "CUDA out of memory: {}", msg),
            CudaError::InvalidValue(msg) => write!(f, "Invalid CUDA value: {}", msg),
            CudaError::UnknownError(msg) => write!(f, "Unknown CUDA error: {}", msg),
        }
    }
}

impl std::error::Error for CudaError {}

impl From<CudaError> for BackendError {
    fn from(err: CudaError) -> Self {
        use crate::error::BackendError;
        BackendError::General(torsh_core::error::GeneralError::RuntimeError(
            err.to_string(),
        ))
    }
}

/// Fallback CUDA backend
#[derive(Debug)]
pub struct CudaBackend;

impl CudaBackend {
    pub fn new(_device_id: usize) -> Result<Self, CudaError> {
        Err(CudaError::RuntimeError(
            "CUDA not available on this system".to_string(),
        ))
    }

    pub fn builder() -> CudaBackendBuilder {
        CudaBackendBuilder
    }

    pub fn devices(&self) -> Result<Vec<CudaDevice>, CudaError> {
        Ok(vec![])
    }
}

/// Fallback CUDA backend builder
#[derive(Debug)]
pub struct CudaBackendBuilder;

impl CudaBackendBuilder {
    pub fn build(self) -> Result<CudaBackend, CudaError> {
        Err(CudaError::RuntimeError(
            "CUDA not available on this system".to_string(),
        ))
    }

    pub fn device(self, _device_id: usize) -> Self {
        self
    }

    pub fn memory_pool(self, _pool_config: impl std::fmt::Debug) -> Self {
        self
    }
}

/// Fallback CUDA device
#[derive(Debug)]
pub struct CudaDevice;

impl CudaDevice {
    pub fn new(_device_id: usize) -> Self {
        CudaDevice
    }
}

/// Fallback CUDA buffer
#[derive(Debug)]
pub struct CudaBuffer<T> {
    _phantom: std::marker::PhantomData<T>,
}

impl<T> CudaBuffer<T> {
    pub fn new(_size: usize) -> Result<Self, CudaError> {
        Err(CudaError::RuntimeError(
            "CUDA not available on this system".to_string(),
        ))
    }
}

/// Fallback CUDA stream
#[derive(Debug)]
pub struct CudaStream;

impl CudaStream {
    pub fn new(_priority: StreamPriority) -> Result<Self, CudaError> {
        Err(CudaError::RuntimeError(
            "CUDA not available on this system".to_string(),
        ))
    }
}

/// Fallback stream priority
#[derive(Debug, Clone, Copy)]
pub enum StreamPriority {
    High,
    Normal,
    Low,
}

/// Fallback CUDA event
#[derive(Debug)]
pub struct CudaEvent;

impl CudaEvent {
    pub fn new() -> Result<Self, CudaError> {
        Err(CudaError::RuntimeError(
            "CUDA not available on this system".to_string(),
        ))
    }
}

/// Fallback CUDA memory manager
#[derive(Debug)]
pub struct CudaMemoryManager;

/// Fallback memory advice
#[derive(Debug)]
pub enum MemoryAdvice {
    ReadMostly,
    PreferredLocation,
    AccessedBy,
}

/// Fallback unified allocation
#[derive(Debug)]
pub struct UnifiedAllocation;

// Essential placeholder types for compilation compatibility
pub struct AsyncEventWaiter;
pub struct CoordinationMetrics;
pub struct CrossStreamBarrier;
pub struct EventMetadata;
pub struct EventPool;
pub struct EventPriority;
pub struct OperationCoordinator;
pub struct OperationType;
pub struct StreamMetrics;
pub struct StreamPool;
pub struct AdvancedStreamPool;
pub struct AllocationStrategy;
pub struct MultiStreamCoordinator;
pub struct PoolMetrics;
pub struct ProfilingReport;
pub struct StreamOrderedAllocator;
pub struct StreamProfiler;
pub struct StreamReport;
pub struct WorkloadType;
pub struct UnifiedBuffer;

// cuDNN fallback types
pub struct ActivationDescriptor;
pub struct ConvolutionDescriptor;
pub struct CudnnHandle;
pub struct CudnnOps;
pub struct FilterDescriptor;
pub struct TensorDescriptor;

// Cooperative groups fallback types
pub struct CooperationPattern;
pub struct CooperativeGroupDescriptor;
pub struct CooperativeGroupType;
pub struct CooperativeGroupsCapabilities;
pub struct CooperativeGroupsContext;
pub struct CooperativeGroupsStats;
pub struct CooperativeKernelConfig;
pub struct CooperativeKernelConfigBuilder;
pub struct CooperativeWorkload;
pub struct KernelPerformanceMetrics;
pub struct MemoryScope;
pub struct SyncFrequency;
pub struct SynchronizationType;

// Mixed precision fallback types
pub struct AmpContext;
pub struct GradientScaler;
pub struct MixedPrecisionTrainer;

// Multi-GPU fallback types
pub struct DataParallel;
pub struct MultiGpuContext;
pub struct ReduceOp;

// Neural ops fallback types
pub struct EnhancedNeuralOps;

// Tensor cores fallback types
pub struct TensorCoreCapability;
pub struct TensorCoreContext;
pub struct TensorCoreDType;
pub struct TensorCoreGemmConfig;
pub struct TensorCoreOp;
pub struct TensorCoreStats;

// Graph execution fallback types
pub struct CudaGraph;
pub struct CudaGraphExec;
pub struct CudaKernelNodeParams;
pub struct CudaMemcpyNodeParams;
pub struct CudaMemsetNodeParams;
pub struct GraphCaptureSession;
pub struct GraphExecutionManager;
pub struct GraphExecutionStats;
pub struct GraphMemoryPool;
pub struct GraphPerformanceSummary;
pub struct MemoryPoolStats;
pub struct PerformanceTrend;

// Scheduler fallback types
pub struct IntelligentStreamScheduler;
pub struct MemoryAccessPattern;
pub struct MultiOperationCoordinator;
pub struct SchedulerMetrics;
pub struct SchedulingDecision;
pub struct SchedulingStrategy;
pub struct SynchronizationRequirements;
pub struct WorkloadCharacteristics;

// Orchestrator fallback types
pub struct ExecutionResult;
pub struct MultiStreamOrchestrator;
pub struct OptimizationResult;
pub struct OrchestratorConfig;
pub struct OrchestratorMetrics;
pub struct RepeatingWorkloadResult;

// Occupancy fallback types
pub struct CudaDeviceOccupancy;
pub struct CudaOccupancyAnalyzer;
pub struct DeviceProperties;
pub struct LimitingFactor;
pub struct OccupancyResult;
pub struct OptimizationHeuristics;
pub struct OptimizedLaunchConfig;
pub struct PerformanceMetrics;
pub struct ResourceUsage;

// High performance kernels fallback types
pub struct ActivationType;
pub struct ConvolutionImplementation;
pub struct HighPerformanceKernelManager;
pub struct KernelOptimizationConfig;
pub struct MatMulImplementation;
pub struct TensorCoreConfiguration;
pub struct TensorCorePrecision;

// Task scheduler fallback types
pub struct DeviceCapability;
pub struct SchedulingStrategyType;
pub struct IntelligentTaskScheduler;
pub struct SchedulableTask;
pub struct SchedulingError;
pub struct SchedulingStatus;
pub struct TaskPriority;
pub struct TaskSubmissionResult;
pub struct TaskType;

// Kernel fusion fallback types
pub struct AdvancedKernelFusionOptimizer;
pub struct FusionStrategyType;
pub struct FusionKernel;
pub struct FusionOperation;
pub struct FusionOptimizationResult;
pub struct FusionPatternType;
pub struct KernelFusionStatus;

// Performance coordinator fallback types
pub struct ComprehensivePerformanceStatus;
pub struct CoordinationError;
pub struct CudaOperationRequest;
pub struct CudaOperationResult;
pub struct CudaPerformanceOptimizationCoordinator;
pub struct PerformanceCoordinatorConfig;

// Backend trait implementations for fallback CUDA backend

impl BackendCore for CudaBackend {
    fn device_type(&self) -> DeviceType {
        DeviceType::Cuda(0)
    }

    fn name(&self) -> &str {
        "CUDA (Fallback)"
    }

    fn is_available(&self) -> BackendResult<bool> {
        Ok(false)
    }

    fn capabilities(&self) -> BackendCapabilities {
        BackendCapabilities {
            max_buffer_size: 0,
            max_compute_units: 0,
            max_workgroup_size: (1, 1, 1),
            supported_dtypes: vec![],
            supports_async: false,
            supports_unified_memory: false,
            supports_sub_buffers: false,
            supports_kernel_caching: false,
            memory_bandwidth_gbps: 0.0,
            compute_throughput_gflops: 0.0,
            extended_capabilities: ExtendedCapabilities::default(),
        }
    }

    fn performance_hints(&self) -> PerformanceHints {
        PerformanceHints {
            preferred_workgroup_size: (1, 1, 1),
            memory_alignment: 1,
            prefer_vectorized: false,
            prefer_async: false,
            optimal_batch_size: 1,
            cache_kernels: false,
        }
    }
}

#[async_trait::async_trait]
impl BackendLifecycle for CudaBackend {
    async fn initialize(&mut self) -> BackendResult<()> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }

    async fn shutdown(&mut self) -> BackendResult<()> {
        Ok(())
    }

    fn is_initialized(&self) -> bool {
        false
    }
}

impl BackendDeviceManager for CudaBackend {
    fn devices(&self) -> BackendResult<Vec<Device>> {
        Ok(vec![])
    }

    fn default_device(&self) -> BackendResult<Device> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }

    fn create_device(&self, _device_id: usize) -> BackendResult<Device> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }

    fn device_count(&self) -> BackendResult<usize> {
        Ok(0)
    }

    fn is_device_available(&self, _device_id: usize) -> bool {
        false
    }
}

impl BackendResourceManager for CudaBackend {
    fn create_buffer(
        &self,
        _device: &Device,
        _descriptor: &BufferDescriptor,
    ) -> BackendResult<Buffer> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }

    fn create_kernel(
        &self,
        _device: &Device,
        _descriptor: &KernelDescriptor,
    ) -> BackendResult<Kernel> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }

    fn memory_manager(
        &self,
        _device: &Device,
    ) -> BackendResult<Box<dyn MemoryManager + Send + Sync>> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }

    fn profiler(&self) -> BackendResult<Box<dyn Profiler + Send + Sync>> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }

    fn create_scoped_buffer(
        &self,
        _device: &Device,
        _descriptor: &BufferDescriptor,
    ) -> BackendResult<Buffer> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }
}

#[async_trait::async_trait]
impl BackendExecutor for CudaBackend {
    async fn synchronize(&self, _device: &Device) -> BackendResult<()> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }

    async fn copy_buffer(
        &self,
        _src: &Buffer,
        _dst: &Buffer,
        _src_offset: usize,
        _dst_offset: usize,
        _size: usize,
    ) -> BackendResult<()> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }

    async fn copy_to_device(
        &self,
        _src: &[u8],
        _dst: &Buffer,
        _dst_offset: usize,
    ) -> BackendResult<()> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }

    async fn copy_from_device(
        &self,
        _src: &Buffer,
        _dst: &mut [u8],
        _src_offset: usize,
    ) -> BackendResult<()> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }

    async fn execute_kernel(
        &self,
        _kernel: &Kernel,
        _buffers: &[&Buffer],
        _uniform_data: &[u8],
        _workgroup_size: (u32, u32, u32),
        _workgroup_count: (u32, u32, u32),
    ) -> BackendResult<()> {
        Err(TorshError::BackendError("CUDA not available".to_string()))
    }
}

impl BackendOperations for CudaBackend {
    fn fft_ops(&self) -> Box<dyn crate::fft::FftOps> {
        Box::new(crate::cpu::fft::CpuFftOps::new(None))
    }

    fn convolution_ops(&self) -> Box<dyn crate::convolution::ConvolutionOps> {
        Box::new(crate::cpu::convolution::CpuConvolutionOps::new(None))
    }

    fn rnn_ops(&self) -> Box<dyn crate::rnn::RnnOps> {
        Box::new(crate::cpu::rnn::CpuRnnOps::new(None))
    }

    fn sparse_ops(&self) -> Box<dyn crate::sparse_ops::SparseOps<f32>> {
        Box::new(crate::sparse_ops::DefaultSparseOps::new(
            crate::Device::new(
                0,
                DeviceType::Cuda(0),
                "CUDA Fallback".to_string(),
                crate::DeviceInfo::default(),
            ),
        ))
    }

    fn quantization_ops(&self) -> Box<dyn crate::quantization::QuantizationOps> {
        Box::new(crate::quantization::CpuQuantizationOps::new())
    }

    fn operations_bundle(&self) -> OperationsBundle {
        OperationsBundle {
            fft: self.fft_ops(),
            convolution: self.convolution_ops(),
            rnn: self.rnn_ops(),
            quantization: self.quantization_ops(),
            sparse: self.sparse_ops(),
        }
    }
}

impl BackendOps for CudaBackend {
    fn backend_type(&self) -> BackendType {
        BackendType::Cuda
    }

    fn available_ops(&self) -> Vec<&str> {
        vec![]
    }

    fn supports_op(&self, _op_name: &str) -> bool {
        false
    }

    fn supports_fft(&self) -> bool {
        false
    }

    fn supports_convolution(&self) -> bool {
        false
    }

    fn supports_rnn(&self) -> bool {
        false
    }

    fn supports_sparse(&self) -> bool {
        false
    }

    fn supports_quantization(&self) -> bool {
        false
    }

    fn operation_capabilities(
        &self,
        _op_name: &str,
    ) -> Option<std::collections::HashMap<String, crate::backend::CapabilityValue>> {
        None
    }
}

impl Backend for CudaBackend {
    fn as_core(&self) -> &dyn BackendCore {
        self
    }

    fn as_lifecycle(&mut self) -> &mut dyn BackendLifecycle {
        self
    }

    fn as_device_manager(&self) -> &dyn BackendDeviceManager {
        self
    }

    fn as_resource_manager(&self) -> &dyn BackendResourceManager {
        self
    }

    fn as_executor(&self) -> &dyn BackendExecutor {
        self
    }

    fn as_operations(&self) -> &dyn BackendOperations {
        self
    }
}
