use core::{
    fmt::Debug,
    intrinsics::unlikely,
    mem::{self, MaybeUninit},
    ptr::null_mut,
    sync::atomic::{compiler_fence, fence, AtomicI16, AtomicPtr, AtomicU64, Ordering},
};

use alloc::{boxed::Box, sync::Arc, vec::Vec};
use log::{debug, info};
use num_traits::FromPrimitive;
use system_error::SystemError;

use crate::{
    arch::CurrentIrqArch,
    exception::bottom_half,
    exception::InterruptArch,
    libs::rwlock::RwLock,
    mm::percpu::{PerCpu, PerCpuVar},
    process::ProcessManager,
    sched::cputime::IrqTime,
    smp::{core::smp_get_processor_id, cpu::ProcessorId},
    time::timer::clock,
};

const MAX_SOFTIRQ_NUM: u64 = 64;
const MAX_SOFTIRQ_RESTART: i32 = 20;

static SOFTIRQ_VECTORS: AtomicPtr<Softirq> = AtomicPtr::new(null_mut());

#[inline(never)]
pub fn softirq_init() -> Result<(), SystemError> {
    info!("Initializing softirq...");
    let softirq = Box::into_raw(Box::new(Softirq::new()));
    if SOFTIRQ_VECTORS
        .compare_exchange(null_mut(), softirq, Ordering::Release, Ordering::Acquire)
        .is_err()
    {
        unsafe { drop(Box::from_raw(softirq)) };
        return Err(SystemError::EBUSY);
    }
    info!("Softirq initialized.");
    return Ok(());
}

#[inline(always)]
pub fn softirq_vectors() -> &'static Softirq {
    let softirq = SOFTIRQ_VECTORS.load(Ordering::Acquire);
    assert!(!softirq.is_null(), "softirq used before initialization");
    unsafe { &*softirq }
}

/// Returns whether the current CPU is executing a softirq callback.
///
/// Unlike `preempt_count`, this does not classify an arbitrary preempt-disabled
/// task as interrupt context. It is also safe before softirq initialization.
#[inline]
pub fn in_softirq() -> bool {
    let softirq = SOFTIRQ_VECTORS.load(Ordering::Acquire);
    !softirq.is_null()
        && unsafe { &*softirq }
            .cpu_running_count()
            .get()
            .load(Ordering::Relaxed)
            > 0
}

/// 软中断向量号码
#[allow(dead_code)]
#[repr(u8)]
#[derive(FromPrimitive, Copy, Clone, Debug, PartialEq, Eq)]
pub enum SoftirqNumber {
    /// 时钟软中断信号
    TIMER = 0,
    VideoRefresh = 1, //帧缓冲区刷新软中断
    TASKLET = 2,
    RCU = 3,
    SRCU = 4,
}

impl From<u64> for SoftirqNumber {
    fn from(value: u64) -> Self {
        return <Self as FromPrimitive>::from_u64(value).unwrap();
    }
}

bitflags! {
    #[derive(Default)]
    pub struct VecStatus: u64 {
        const TIMER = 1 << 0;
        const VIDEO_REFRESH = 1 << 1;
        const TASKLET = 1 << 2;
        const RCU = 1 << 3;
        const SRCU = 1 << 4;
    }
}

impl From<SoftirqNumber> for VecStatus {
    fn from(value: SoftirqNumber) -> Self {
        return Self::from_bits_truncate(1 << (value as u64));
    }
}

pub trait SoftirqVec: Send + Sync + Debug {
    fn run(&self);
}

#[derive(Debug)]
pub struct Softirq {
    table: RwLock<[Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize]>,
    /// Per-CPU pending vector. IRQ exclusion gives the local read/clear
    /// transaction its ordering; atomics avoid manufacturing aliased mutable
    /// references to a global array across CPUs.
    cpu_pending: PerCpuVar<AtomicU64>,
    /// 软中断嵌套层数（per cpu）
    cpu_running_count: PerCpuVar<AtomicI16>,
}
impl Softirq {
    /// 每个CPU最大嵌套的软中断数量
    const MAX_RUNNING_PER_CPU: i16 = 3;
    fn new() -> Softirq {
        let mut data: [MaybeUninit<Option<Arc<dyn SoftirqVec>>>; MAX_SOFTIRQ_NUM as usize] =
            unsafe { MaybeUninit::uninit().assume_init() };

        for i in 0..MAX_SOFTIRQ_NUM {
            data[i as usize] = MaybeUninit::new(None);
        }

        let data: [Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize] = unsafe {
            mem::transmute::<_, [Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize]>(data)
        };

        let mut percpu_count = Vec::with_capacity(PerCpu::MAX_CPU_NUM as usize);
        percpu_count.resize_with(PerCpu::MAX_CPU_NUM as usize, || AtomicI16::new(0));
        let cpu_running_count = PerCpuVar::new(percpu_count).unwrap();

        let mut pending = Vec::with_capacity(PerCpu::MAX_CPU_NUM as usize);
        pending.resize_with(PerCpu::MAX_CPU_NUM as usize, || AtomicU64::new(0));
        let cpu_pending = PerCpuVar::new(pending).unwrap();

        return Softirq {
            table: RwLock::new(data),
            cpu_pending,
            cpu_running_count,
        };
    }

    fn cpu_running_count(&self) -> &PerCpuVar<AtomicI16> {
        return &self.cpu_running_count;
    }

    #[inline]
    fn pending_for(&self, cpu_id: ProcessorId) -> &AtomicU64 {
        // `cpu_id` comes from the architecture CPU-id provider and PerCpuVar
        // was initialized for the same CPU set.  The returned value is atomic,
        // so exposing a shared reference across CPUs does not create aliases.
        unsafe { self.cpu_pending.force_get(cpu_id) }
    }

    /// @brief 注册软中断向量
    ///
    /// @param softirq_num 中断向量号
    ///
    /// @param hanlder 中断函数对应的结构体
    pub fn register_softirq(
        &self,
        softirq_num: SoftirqNumber,
        handler: Arc<dyn SoftirqVec>,
    ) -> Result<i32, SystemError> {
        // debug!("register_softirq softirq_num = {:?}", softirq_num as u64);

        // let self = &mut SOFTIRQ_VECTORS.lock();
        // 判断该软中断向量是否已经被注册
        let mut table_guard = self.table.write_irqsave();
        if table_guard[softirq_num as usize].is_some() {
            // debug!("register_softirq failed");

            return Err(SystemError::EINVAL);
        }
        table_guard[softirq_num as usize] = Some(handler);
        drop(table_guard);

        // debug!(
        //     "register_softirq successfully, softirq_num = {:?}",
        //     softirq_num as u64
        // );
        compiler_fence(Ordering::SeqCst);
        return Ok(0);
    }

    /// @brief 解注册软中断向量
    ///
    /// @param irq_num 中断向量号码  
    #[allow(dead_code)]
    pub fn unregister_softirq(&self, softirq_num: SoftirqNumber) {
        // debug!("unregister_softirq softirq_num = {:?}", softirq_num as u64);
        let mut table_guard = self.table.write_irqsave();
        // 将软中断向量清空
        table_guard[softirq_num as usize] = None;
        drop(table_guard);
        // 将对应位置的pending和runing都置0
        // self.running.lock().set(VecStatus::from(softirq_num), false);
        // 将对应CPU的pending置0
        compiler_fence(Ordering::SeqCst);
        self.pending_for(smp_get_processor_id())
            .fetch_and(!VecStatus::from(softirq_num).bits(), Ordering::SeqCst);
        compiler_fence(Ordering::SeqCst);
    }

    #[inline(never)]
    fn do_softirq(&self) {
        ProcessManager::preempt_disable();
        let _preempt_guard = SoftirqPreemptGuard;
        if self.cpu_running_count().get().load(Ordering::SeqCst) >= Self::MAX_RUNNING_PER_CPU {
            // 当前CPU的软中断嵌套层数已经达到最大值，不再执行
            return;
        }
        // 创建一个RunningCountGuard，当退出作用域时，会自动将cpu_running_count减1
        let _count_guard = RunningCountGuard::new(self.cpu_running_count());
        // Match Linux softirq context accounting: softirq handlers run with a
        // non-zero preempt count even though local IRQs may be enabled below.
        // This prevents a timer IRQ nested inside task-context softirq handling
        // from scheduling away before the softirq handler returns.
        // TODO pcb的flags未修改
        let end = clock() + 500 * 2;
        let cpu_id = smp_get_processor_id();
        let mut max_restart = MAX_SOFTIRQ_RESTART;
        loop {
            compiler_fence(Ordering::SeqCst);
            let pending = self.pending_for(cpu_id).swap(0, Ordering::SeqCst);
            compiler_fence(Ordering::SeqCst);

            unsafe { CurrentIrqArch::interrupt_enable() };
            if pending != 0 {
                for i in 0..MAX_SOFTIRQ_NUM {
                    if pending & (1 << i) == 0 {
                        continue;
                    }

                    let table_guard = self.table.read_irqsave();
                    let softirq_func = table_guard[i as usize].clone();
                    drop(table_guard);
                    if softirq_func.is_none() {
                        continue;
                    }

                    let prev_count: usize = ProcessManager::current_pcb().preempt_count();

                    softirq_func.as_ref().unwrap().run();
                    if unlikely(prev_count != ProcessManager::current_pcb().preempt_count()) {
                        debug!(
                            "entered softirq {:?} with preempt_count {:?},exited with {:?}",
                            i,
                            prev_count,
                            ProcessManager::current_pcb().preempt_count()
                        );
                        unsafe { ProcessManager::current_pcb().set_preempt_count(prev_count) };
                    }
                }
            }
            unsafe { CurrentIrqArch::interrupt_disable() };
            max_restart -= 1;
            compiler_fence(Ordering::SeqCst);
            let has_pending = self.pending_for(cpu_id).load(Ordering::SeqCst) != 0;
            compiler_fence(Ordering::SeqCst);
            if has_pending && clock() < end && max_restart > 0 {
                continue;
            }
            // Pending work left after the time/restart budget remains set for
            // the next IRQ exit (or a future softirqd implementation).
            break;
        }
    }

    pub fn raise_softirq(&self, softirq_num: SoftirqNumber) {
        let guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
        let processor_id = smp_get_processor_id();

        self.pending_for(processor_id)
            .fetch_or(VecStatus::from(softirq_num).bits(), Ordering::SeqCst);

        compiler_fence(Ordering::SeqCst);

        drop(guard);
        // debug!("raise_softirq exited");
    }

    #[allow(dead_code)]
    pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) {
        compiler_fence(Ordering::SeqCst);
        self.pending_for(smp_get_processor_id())
            .fetch_and(!VecStatus::from(softirq_num).bits(), Ordering::SeqCst);
        compiler_fence(Ordering::SeqCst);
    }
}

/// 当前CPU的软中断嵌套层数的计数器守卫
///
/// 当进入作用域时，会自动将cpu_running_count加1，
/// 当退出作用域时，会自动将cpu_running_count减1
struct RunningCountGuard<'a> {
    cpu_running_count: &'a AtomicI16,
}

impl<'a> RunningCountGuard<'a> {
    fn new(cpu_running_count: &'a PerCpuVar<AtomicI16>) -> RunningCountGuard<'a> {
        let local_count = cpu_running_count.get();
        local_count.fetch_add(1, Ordering::SeqCst);
        return RunningCountGuard {
            cpu_running_count: local_count,
        };
    }
}

impl Drop for RunningCountGuard<'_> {
    fn drop(&mut self) {
        self.cpu_running_count.fetch_sub(1, Ordering::SeqCst);
    }
}

struct SoftirqPreemptGuard;

impl Drop for SoftirqPreemptGuard {
    fn drop(&mut self) {
        ProcessManager::preempt_enable();
    }
}

/// 处理 softirq。
///
/// 如果本 CPU BH 被禁用，则直接返回，保留 pending 让 `LocalBhDisableGuard` 的 drop
/// 或未来某次 IRQ 退出点补跑。
#[inline(never)]
/// Run pending softirqs for the current CPU.
///
/// Callers must enter with local IRQs disabled.  Handlers may temporarily
/// enable IRQs, but this function always returns with them disabled.
pub(crate) fn do_softirq() {
    // BH disabled => 不执行 softirq（避免进程态持锁被打断后在 softirq 再取锁死锁）
    if bottom_half::is_local_bh_disabled() {
        return;
    }

    fence(Ordering::SeqCst);
    IrqTime::irqtime_start();
    softirq_vectors().do_softirq();
    IrqTime::irqtime_account_irq(ProcessManager::current_pcb(), false);
    fence(Ordering::SeqCst);
}
