use core::cell::{RefCell, RefMut, UnsafeCell};
use core::ops::{Deref, DerefMut};
use riscv::register::sstatus;
use spin::Lazy;

/*
/// Wrap a static data structure inside it so that we are
/// able to access it without any `unsafe`.
///
/// We should only use it in uniprocessor.
///
/// In order to get mutable reference of inner data, call
/// `exclusive_access`.
pub struct UPSafeCell<T> {
    /// inner data
    inner: RefCell<T>,
}

unsafe impl<T> Sync for UPSafeCell<T> {}

impl<T> UPSafeCell<T> {
    /// User is responsible to guarantee that inner struct is only used in
    /// uniprocessor.
    pub unsafe fn new(value: T) -> Self {
        Self {
            inner: RefCell::new(value),
        }
    }
    /// Panic if the data has been borrowed.
    pub fn exclusive_access(&self) -> RefMut<'_, T> {
        self.inner.borrow_mut()
    }
}
*/

/// 单处理器环境下的内部可变性容器（原始版本）。
///
/// 这个类型绕过了 Rust 的借用检查，仅适用于单处理器环境。
pub struct UPSafeCellRaw<T> {
    inner: UnsafeCell<T>,
}

// SAFETY: 此类型仅用于单处理器环境，不会发生数据竞争。
// 使用者需要确保不会在单处理器上产生重入问题。
unsafe impl<T> Sync for UPSafeCellRaw<T> {}

impl<T> UPSafeCellRaw<T> {
    /// 创建一个新的 `UPSafeCellRaw`。
    ///
    /// # Safety
    ///
    /// 调用者必须确保此类型仅在单处理器环境下使用，
    /// 且不会在持有可变引用时发生重入。
    pub unsafe fn new(_value: T) -> Self {
        unimplemented!()
        // Self {
        //     inner: UnsafeCell::new(value),
        // }
    }

    /// 获取内部值的可变引用。
    ///
    /// 注意：此函数不进行借用检查，调用者需要确保不会产生多个可变引用。
    pub fn get_mut(&self) -> &mut T {
        // SAFETY: 单处理器环境下，只要调用者确保不重入，就不会产生数据竞争。
        // 此函数的安全性由 UPSafeCellRaw::new 的 unsafe 约定保证。
        unsafe { &mut (*self.inner.get()) }
    }
}

/// 中断屏蔽信息
pub struct IntrMaskingInfo {
    nested_level: usize,
    sie_before_masking: bool,
}

/// 全局中断屏蔽信息。
///
/// SAFETY: 此静态变量仅在单处理器内核中使用，通过中断屏蔽保证访问安全。
pub static INTR_MASKING_INFO: Lazy<UPSafeCellRaw<IntrMaskingInfo>> = Lazy::new(|| {
    // SAFETY: 内核运行在单处理器环境下
    unsafe { UPSafeCellRaw::new(IntrMaskingInfo::new()) }
});

impl IntrMaskingInfo {
    pub fn new() -> Self {
        Self {
            nested_level: 0,
            sie_before_masking: false,
        }
    }

    /// 进入中断屏蔽区域。
    pub fn enter(&mut self) {
        let sie = sstatus::read().sie();
        // SAFETY: 清除 sstatus.SIE 位以禁用中断，这是单处理器同步的标准做法
        unsafe {
            sstatus::clear_sie();
        }
        if self.nested_level == 0 {
            // 只在最外层临界区记录进入前状态，支持可重入的“嵌套关中断”。
            self.sie_before_masking = sie;
        }
        self.nested_level += 1;
    }

    /// 退出中断屏蔽区域。
    pub fn exit(&mut self) {
        self.nested_level -= 1;
        if self.nested_level == 0 && self.sie_before_masking {
            // SAFETY: 恢复 sstatus.SIE 位以重新启用中断
            unsafe {
                sstatus::set_sie();
            }
        }
    }
}

/// 带中断屏蔽的内部可变性容器。
///
/// 在访问内部数据时自动禁用中断，保证单处理器环境下的数据安全。
pub struct UPIntrFreeCell<T> {
    /// inner data
    inner: RefCell<T>,
}

// SAFETY: 此类型通过中断屏蔽保证单处理器环境下不会发生数据竞争。
// RefCell 的动态借用检查会在运行时捕获重入错误。
unsafe impl<T> Sync for UPIntrFreeCell<T> {}

/// A wrapper type for a mutably borrowed value from a RefCell<T>
pub struct UPIntrRefMut<'a, T>(Option<RefMut<'a, T>>);

impl<T> UPIntrFreeCell<T> {
    /// 创建一个新的 `UPIntrFreeCell`。
    ///
    /// # Safety
    ///
    /// 调用者必须确保此类型仅在单处理器环境下使用。
    pub unsafe fn new(_value: T) -> Self {
        unimplemented!()
        // Self {
        //     inner: RefCell::new(value),
        // }
    }

    /// Panic if the data has been borrowed.
    pub fn exclusive_access(&self) -> UPIntrRefMut<'_, T> {
        // 先关中断，再借用 RefCell，确保单核下不会被时钟中断打断而重入。
        INTR_MASKING_INFO.get_mut().enter();
        UPIntrRefMut(Some(self.inner.borrow_mut()))
    }
    /// exclusive_session
    pub fn exclusive_session<F, V>(&self, f: F) -> V
    where
        F: FnOnce(&mut T) -> V,
    {
        let mut inner = self.exclusive_access();
        f(inner.deref_mut())
    }
}

impl<'a, T> Drop for UPIntrRefMut<'a, T> {
    fn drop(&mut self) {
        self.0 = None;
        INTR_MASKING_INFO.get_mut().exit();
    }
}

impl<'a, T> Deref for UPIntrRefMut<'a, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        self.0.as_ref().unwrap().deref()
    }
}
impl<'a, T> DerefMut for UPIntrRefMut<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.0.as_mut().unwrap().deref_mut()
    }
}
