use super::core::ConnIoSlot;
use crate::CodecLayer;
use crate::SlotGen;
use crate::WriteBufStorage;
use dambi::AlwaysInit;
use dope_core::FixedFd;

pub(crate) const INGRESS_BUF_CAP: usize = 8 * 1024;
pub const WRITE_BUF_CAP: usize = 16 * 1024;
pub(crate) const WRITE_ROOM_MIN: usize = 256;

#[derive(Clone, Copy, Debug, Default)]
pub(crate) struct ConnFlags(u8);

impl ConnFlags {
    pub(crate) const LIVE: u8 = 1 << 0;
    pub(crate) const CLOSE_AFTER: u8 = 1 << 2;
    pub(crate) const PARKED: u8 = 1 << 3;

    #[inline]
    pub(crate) const fn empty() -> Self {
        Self(0)
    }

    #[inline]
    pub(crate) const fn contains(self, bit: u8) -> bool {
        (self.0 & bit) == bit
    }

    #[inline]
    #[allow(dead_code)]
    pub(crate) const fn intersects(self, mask: u8) -> bool {
        (self.0 & mask) != 0
    }

    #[inline]
    pub(crate) fn set(&mut self, bit: u8, on: bool) {
        if on {
            self.0 |= bit;
        } else {
            self.0 &= !bit;
        }
    }
}

#[repr(C, align(64))]
pub(crate) struct Conn {
    pub(super) fd: FixedFd,
    pub(super) generation: SlotGen,
    pub(super) flags: ConnFlags,
    pub(super) write_head: u16,
    pub(super) write_tail: u16,
    pub(super) write_inflight_end: u16,
    pub(super) ingress_head: u16,
    pub(super) ingress_tail: u16,
    pub(super) parse_phase: u8,
    pub(super) body_needed: u32,
    pub(super) pending_body_ptr: *const u8,
    pub(super) pending_body_len: u32,
    pub(super) large_inflight: u32,
    pub(super) large_tail: u32,
    _pad: [u8; 4],
}

const _: () = assert!(std::mem::size_of::<Conn>() == 64);
const _: () = assert!(std::mem::align_of::<Conn>() == 64);

impl Conn {
    pub(crate) fn reset_for_reuse(&mut self) {
        self.generation = self.generation.checked_add(1).unwrap_or(SlotGen::MIN);
        self.flags = ConnFlags::empty();
        self.write_head = 0;
        self.write_tail = 0;
        self.write_inflight_end = 0;
        self.ingress_head = 0;
        self.ingress_tail = 0;
        self.parse_phase = 0;
        self.body_needed = 0;
        self.pending_body_ptr = std::ptr::null();
        self.pending_body_len = 0;
        self.large_inflight = 0;
        self.large_tail = 0;
    }
}

#[repr(C, align(64))]
pub(crate) struct BufSlot<W: WriteBufStorage> {
    pub(super) ingress_buf: [u8; INGRESS_BUF_CAP],
    pub(super) write_buf: W,

    pub(super) pending_iovs: [libc::iovec; 4],
    pub(super) pending_msghdr: libc::msghdr,

    pub(super) staged_gather_cookie: *const u8,
}

unsafe impl<W: WriteBufStorage> Send for BufSlot<W> {}
unsafe impl<W: WriteBufStorage> Sync for BufSlot<W> {}

const _: () = assert!(std::mem::align_of::<BufSlot<crate::codec::WriteBufArr>>() == 64);

#[repr(C, align(64))]
pub(crate) struct CoreSlot<L: CodecLayer, U: 'static> {
    pub(super) conn: Conn,
    pub(super) io: ConnIoSlot,
    pub(super) buf: BufSlot<L::WriteBuf>,
    pub(super) codec_state: AlwaysInit<L::ConnState>,
    pub(super) user: AlwaysInit<U>,
}

unsafe impl<L: CodecLayer, U: 'static> Send for CoreSlot<L, U> {}
unsafe impl<L: CodecLayer, U: 'static> Sync for CoreSlot<L, U> {}
