use std::{marker::PhantomPinned, pin::Pin, ptr::copy_nonoverlapping};

use cyberex::{void::*, xself::*};

use crate::{
    define::{CESStreamInfo, EsPkg},
    sys::*,
};

extern "C" fn DataCallBack(
    data: *const ::std::os::raw::c_uchar,
    len: ::std::os::raw::c_int,
    info: *const ESStreamInfo,
    user: *mut ::std::os::raw::c_void,
) {
    let pkgs = opacue_to_mut::<Vec<EsPkg>>(user.cast());

    pkgs.push(EsPkg {
        payload: {
            let payload = vec![0u8; len as _];
            unsafe {
                copy_nonoverlapping(data, payload.as_ptr() as _, len as _);
            }
            payload
        },
        info: unsafe { std::ptr::read(info) },
    });
}

pub struct Dmuxer {
    ptr: HyVoid<()>,
    _pin: PhantomPinned,
}

impl Dmuxer {
    pub fn new() -> Pin<Box<Self>> {
        Box::pin(Self {
            ptr: unsafe { HyVoid::from_ptr(ffDmCreate()) },
            _pin: PhantomPinned,
        })
    }
    pub fn write(self: &mut Pin<Box<Self>>, data: &[u8], info: &CESStreamInfo) -> Vec<EsPkg> {
        let this = unsafe { self_mut_from_pinbox(self) };
        let mut pkgs = Box::<std::vec::Vec<EsPkg>>::default();

        unsafe {
            ffDmStreamInput(
                this.ptr.as_ptr(),
                data.as_ptr(),
                data.len() as i32,
                info as *const _,
                0 as _, // NO-USE just placeholder
                mut_to_opacue(pkgs.as_mut()),
                Some(DataCallBack),
                None,
            );
        }

        *pkgs
    }
}
impl Drop for Dmuxer {
    fn drop(&mut self) {
        unsafe { ffDmDestroy(self.ptr.as_ptr()) }
    }
}