use crate::errors::*;
use error_stack::ResultExt;
use mnn_bridge::ndarray::NdarrayToMnn;
use std::path::Path;

pub struct FaceDetection {
    handle: mnn_sync::SessionHandle,
}

impl FaceDetection {
    pub fn new(path: impl AsRef<Path>) -> Result<Self> {
        let model = std::fs::read(path)
            .change_context(Error)
            .attach_printable("Failed to read model file")?;
        Self::new_from_bytes(&model)
    }

    pub fn new_from_bytes(model: &[u8]) -> Result<Self> {
        tracing::info!("Loading face detection model from bytes");
        let mut model = mnn::Interpreter::from_bytes(model)
            .map_err(|e| e.into_inner())
            .change_context(Error)
            .attach_printable("Failed to load model from bytes")?;
        model.set_session_mode(mnn::SessionMode::Release);
        let bc = mnn::BackendConfig::default().with_memory_mode(mnn::MemoryMode::High);
        let sc = mnn::ScheduleConfig::new()
            .with_type(mnn::ForwardType::CPU)
            .with_backend_config(bc);
        tracing::info!("Creating session handle for face detection model");
        let handle = mnn_sync::SessionHandle::new(model, sc)
            .change_context(Error)
            .attach_printable("Failed to create session handle")?;
        Ok(FaceDetection { handle })
    }

    pub fn detect_faces(&self, image: ndarray::Array3<u8>) -> Result<ndarray::Array2<u8>> {
        use mnn_bridge::ndarray::MnnToNdarray;
        let output = self
            .handle
            .run(move |sr| {
                let tensor = image
                    .as_mnn_tensor()
                    .ok_or_else(|| Error)
                    .attach_printable("Failed to convert ndarray to mnn tensor")
                    .change_context(mnn::error::ErrorKind::TensorError)?;
                let (intptr, session) = sr.both_mut();
                tracing::trace!("Copying input tensor to host");
                // let input = intptr.input::<u8>(session, "input")?;
                // dbg!(input.shape());
                // let mut t = input.create_host_tensor_from_device(false);
                // tensor.copy_to_host_tensor(&mut t)?;
                //
                // intptr.run_session(&session)?;
                // let output = intptr.output::<u8>(&session, "output").unwrap();
                // let output_tensor = output.create_host_tensor_from_device(true);
                // let output_array = output_tensor
                //     .try_as_ndarray()
                //     .change_context(mnn::error::ErrorKind::TensorError)?
                //     .to_owned();
                // Ok(output_array)
                Ok(ndarray::Array2::<u8>::zeros((1, 1))) // Placeholder for actual output
            })
            .map_err(|e| e.into_inner())
            .change_context(Error);
        output
    }
}
