use std::io;
use std::os::{fd::AsFd, unix::io::OwnedFd};

use rustix::fs::{fcntl_add_seals, ftruncate, memfd_create, MemfdFlags, SealFlags};
use wayland_client::protocol::wl_buffer;
use wayland_client::protocol::wl_shm::Format;
use wayland_client::Dispatch;
use wayland_client::{
    protocol::{wl_shm, wl_shm_pool},
    QueueHandle,
};

/// Create an empty buffer (e.g.: filled with `\0`).
pub fn empty_buffer<T, U, V>(
    wl_shm: &wl_shm::WlShm,
    width: u32,
    height: u32,
    format: Format,
    qh: &QueueHandle<T>,
) -> io::Result<(wl_buffer::WlBuffer, OwnedFd)>
where
    T: Dispatch<wl_shm_pool::WlShmPool, U> + Dispatch<wl_buffer::WlBuffer, V> + 'static,
    U: Sync + Send + Default + 'static,
    V: Sync + Send + Default + 'static,
{
    let memfile = memfd_create("buffer", MemfdFlags::ALLOW_SEALING)?;
    ftruncate(&memfile, (width * height * 4).into())?;
    fcntl_add_seals(&memfile, SealFlags::GROW | SealFlags::SHRINK)?;

    let size = (width * height * 4) as i32;
    let pool = wl_shm.create_pool(memfile.as_fd(), size, qh, U::default());
    let buffer = pool.create_buffer(
        0,
        width as i32,
        height as i32,
        (width * 4) as i32,
        format,
        qh,
        V::default(),
    );
    pool.destroy();

    Ok((buffer, memfile))
}
