use super::{poll::PollFlags, vfs::file::File};
use crate::libs::{mutex::Mutex, spinlock::SpinLock};
use alloc::sync::Weak;
use core::fmt::Debug;
use core::sync::atomic::{AtomicBool, Ordering};
use event_poll::{EPollItemList, EPollKey, EventPoll, ReadyState};
use system_error::SystemError;

pub mod event_poll;
pub mod fs;

/// 与C兼容的Epoll事件结构体
#[derive(Copy, Clone, Default)]
#[repr(packed)]
#[repr(C)]
pub struct EPollEvent {
    /// 表示触发的事件
    events: u32,
    /// 内核态不使用该字段，该字段由用户态自由使用，在事件发生时内核将会原样返回
    data: u64,
}

impl Debug for EPollEvent {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        let events = self.events;
        let u64 = self.data;
        f.debug_struct("epoll_event")
            .field("events", &events)
            .field("data", &u64)
            .finish()
    }
}

impl EPollEvent {
    pub fn set_events(&mut self, events: u32) {
        self.events = events;
    }

    pub fn events(&self) -> u32 {
        self.events
    }

    pub fn set_data(&mut self, data: u64) {
        self.data = data;
    }

    pub fn data(&self) -> u64 {
        self.data
    }
}

/// EpollItem表示的是Epoll所真正管理的对象
/// 每当用户向Epoll添加描述符时都会注册一个新的EpollItem，EpollItem携带了一些被监听的描述符的必要信息
#[derive(Debug)]
pub struct EPollItem {
    /// 对应的Epoll
    epoll: Weak<Mutex<EventPoll>>,
    /// 直接引用 EventPoll 的 ready_state，使回调路径绕过外层 Mutex。
    /// 对标 Linux 中 ep_poll_callback 仅获取 ep->lock 而不获取 ep->mtx 的设计。
    ready_state: Weak<SpinLock<ReadyState>>,
    /// 直接引用 EventPoll 的 poll_epitems，使嵌套 epoll 的向上传播无需获取外层 Mutex。
    poll_epitems: Weak<EPollItemList>,
    /// 用户注册的事件
    /// 使用 irqsave SpinLock 而非 RwSem，因为 wakeup_epoll 回调路径可能在
    /// hardirq 上下文中执行（例如 timer IRQ → signal → signalfd → epoll），
    /// RwSem 是可睡眠锁，在 hardirq 中使用会导致死锁。
    /// 对标 Linux 中 epitem.event 由 ep->lock (spin_lock_irqsave) 保护的设计。
    event: SpinLock<EPollEvent>,
    /// 对应的文件
    file: Weak<File>,
    key: EPollKey,
    /// Whether callbacks may still publish this registration to the ready list.
    active: AtomicBool,
}

impl EPollItem {
    #[allow(private_interfaces)]
    pub(super) fn new(
        epoll: Weak<Mutex<EventPoll>>,
        ready_state: Weak<SpinLock<ReadyState>>,
        poll_epitems: Weak<EPollItemList>,
        key: EPollKey,
        events: EPollEvent,
        file: Weak<File>,
    ) -> Self {
        Self {
            epoll,
            ready_state,
            poll_epitems,
            key,
            event: SpinLock::new(events),
            file,
            active: AtomicBool::new(true),
        }
    }

    pub fn epoll(&self) -> Weak<Mutex<EventPoll>> {
        self.epoll.clone()
    }

    /// 获取 ready_state 的 Weak 引用，用于回调路径直接访问就绪状态。
    #[allow(dead_code)]
    pub(crate) fn ready_state(&self) -> Weak<SpinLock<ReadyState>> {
        self.ready_state.clone()
    }

    /// 获取 poll_epitems 的 Weak 引用，用于嵌套 epoll 的向上传播。
    #[allow(dead_code)]
    pub(crate) fn poll_epitems(&self) -> Weak<EPollItemList> {
        self.poll_epitems.clone()
    }

    pub(crate) fn is_active(&self) -> bool {
        self.active.load(Ordering::Relaxed)
    }

    pub(crate) fn deactivate(&self) {
        self.active.store(false, Ordering::Relaxed);
    }

    pub fn event(&self) -> &SpinLock<EPollEvent> {
        &self.event
    }

    pub fn file(&self) -> Weak<File> {
        self.file.clone()
    }

    pub(crate) fn key(&self) -> EPollKey {
        self.key
    }

    /// ## 通过epoll_item来执行绑定文件的poll方法，并获取到感兴趣的事件
    ///
    /// 返回与用户注册的事件掩码相交的就绪事件
    pub(super) fn ep_item_poll(&self) -> EPollEventType {
        let Some(file) = self.file.upgrade() else {
            return EPollEventType::empty();
        };

        // 对于不支持poll的普通文件/目录，返回默认掩码（总是就绪）
        // 需要与用户注册的事件掩码相交，保持与普通文件路径的一致性
        if file.is_always_ready() {
            let interested = self.event.lock_irqsave().events;
            return EPollEventType::from_bits_truncate(
                Self::default_poll_mask().bits() & interested,
            );
        }

        match file.poll() {
            Ok(events) => {
                let interested = self.event.lock_irqsave().events;
                EPollEventType::from_bits_truncate(events as u32 & interested)
            }
            Err(_) => EPollEventType::empty(),
        }
    }

    /// 返回默认的poll掩码，用于不支持poll的普通文件
    ///
    /// 对应Linux内核的 DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
    #[inline]
    pub(super) fn default_poll_mask() -> EPollEventType {
        PollFlags::DEFAULT_POLLMASK.into()
    }
}

/// ## epoll_ctl函数的参数
#[derive(Debug, PartialEq)]
pub enum EPollCtlOption {
    /// 注册新的文件描述符到epfd
    Add,
    /// 将对应的文件描述符从epfd中删除
    Del,
    /// 修改已经注册的文件描述符的监听事件
    Mod,
}

impl EPollCtlOption {
    pub fn from_op_num(op: usize) -> Result<Self, SystemError> {
        match op {
            1 => Ok(Self::Add),
            2 => Ok(Self::Del),
            3 => Ok(Self::Mod),
            _ => Err(SystemError::EINVAL),
        }
    }
}

bitflags! {
    #[allow(dead_code)]
    pub struct EPollEventType: u32 {
        /// 对应的描述符有新的数据可读时会触发
        const EPOLLIN = 0x00000001;
        /// 对应的描述符有紧急数据可读时会触发
        const EPOLLPRI = 0x00000002;
        /// 对应的描述符可以写入数据时会触发
        const EPOLLOUT = 0x00000004;
        /// 对应的描述符发生错误时会触发
        const EPOLLERR = 0x00000008;
        /// 对应的描述符被挂断（连接关闭）时会触发
        const EPOLLHUP = 0x00000010;
        /// 对应的描述符不是一个有效的文件描述符时会触发
        const EPOLLNVAL = 0x00000020;
        /// 普通数据可读，类似于`EPOLLIN`
        const EPOLLRDNORM = 0x00000040;
        /// 优先级带外数据可读
        const EPOLLRDBAND = 0x00000080;
        /// 普通数据可写，类似于'EPOLLOUT'
        const EPOLLWRNORM = 0x00000100;
        /// 优先级带外数据可写
        const EPOLLWRBAND = 0x00000200;
        /// 通过消息队列收到消息时会触
        const EPOLLMSG = 0x00000400;
        /// 对应的描述符被挂断（连接关闭）的一端发送了 FIN 时会触发(读关闭)
        const EPOLLRDHUP = 0x00002000;

        /// 以下为额外选项
        ///
        /// 特定选项，用于异步 I/O，目前未实现
        const EPOLL_URING_WAKE = 1u32 << 27;
        /// 设置epoll为独占模式
        const EPOLLEXCLUSIVE = 1u32 << 28;
        ///  允许在系统挂起时唤醒 epoll，通常用于通过 eventfd 或 timerfd 唤醒 epoll,(通常与电源管理相关，未实现)
        const EPOLLWAKEUP = 1u32 << 29;
        /// 表示只监听一次事件，之后需要重新添加
        const EPOLLONESHOT = 1u32 << 30;

        /// 启用边缘触发模式(即只有下次触发事件时才会通过epoll_wait返回)，
        /// 对应为水平触发(默认)，水平触发模式下若这次未处理完数据，那epoll还会将其加入自己的就绪队列
        const EPOLLET = 1u32 << 31;

        /// 以下为组合码
        const EPOLLINOUT_BITS = Self::EPOLLIN.bits | Self::EPOLLOUT.bits;
        const EPOLLEXCLUSIVE_OK_BITS =
            Self::EPOLLINOUT_BITS.bits
            | Self::EPOLLERR.bits
            | Self::EPOLLHUP.bits
            | Self::EPOLLWAKEUP.bits
            | Self::EPOLLET.bits
            | Self::EPOLLEXCLUSIVE.bits;

        const EP_PRIVATE_BITS =
            Self::EPOLLWAKEUP.bits
            | Self::EPOLLONESHOT.bits
            | Self::EPOLLET.bits
            | Self::EPOLLEXCLUSIVE.bits;

        /// 表示epoll已经被释放，但是在目前的设计中未用到
        const POLLFREE = 0x4000;

        /// listen状态的socket可以接受连接
        const EPOLL_LISTEN_CAN_ACCEPT = Self::EPOLLIN.bits | Self::EPOLLRDNORM.bits;
    }
}

impl EPollEventType {
    pub fn filter(&self, events: &EPollEventType) -> bool {
        self.intersects(*events)
    }
}
