use crate::pixelmsgs::PixelStringMsgs;
use address::Host;
use io_uring::{opcode, types, IoUring, Submitter};
use libc::c_void;
use libc::iovec;
use std::{io::Write, net::TcpStream, os::fd::AsRawFd};

pub struct FlutR {
    stream: TcpStream,
    stream_fd: i32,
    msgs: PixelStringMsgs,
}

impl FlutR {
    pub fn new(host: Host, port: u16, msgs: PixelStringMsgs) -> Result<Self, std::io::Error> {
        let stream = TcpStream::connect(format!("{host}:{port}"))?;
        let stream_fd = stream.as_raw_fd();
        Ok(FlutR {
            stream,
            stream_fd,
            msgs,
        })
    }

    pub fn flut(&mut self) {
        unsafe {
            self.write_io_uring();
            //self.write_sequential();
        }
    }

    fn write_sequential(&mut self) {
        loop {
            for msg in self.msgs.clone() {
                let _ = self.stream.write(&msg);
            }
            let _ = self.stream.flush();
        }
    }

    unsafe fn write_io_uring(&mut self) {
        let mut ring = IoUring::new(8).unwrap();

        let buffer_len: usize = self.msgs.len() * 11;
        let buffer: iovec = iovec {
            iov_base: self.msgs.as_mut_ptr() as *mut c_void,
            iov_len: buffer_len,
        };
        ring.submitter().register_buffers(&[buffer]);

        let write_op = opcode::WriteFixed::new(
            io_uring::types::Fd(self.stream_fd),
            buffer.iov_base as *const u8,
            buffer_len as u32,
            0,
        )
        .build();

        loop {
            while ring.submission().is_full() {
                ring.submission().sync();
            }
            ring.submission().push(&write_op).unwrap();
            ring.submit().unwrap();
        }
    }
}
