use std::collections::BTreeMap;
use crate::*;
pub struct Internal {
    pub input_length: usize,
    pub input: *const u8,
    pub output_offset: usize,
    pub output_length: usize,
    pub wasi: Option<Wasi>,
    pub http_status: u16,
    pub last_error: std::cell::RefCell<Option<std::ffi::CString>>,
    pub vars: BTreeMap<String, Vec<u8>>,
    pub memory: *mut PluginMemory,
}
pub trait InternalExt {
    fn memory(&self) -> &PluginMemory;
    fn memory_mut(&mut self) -> &mut PluginMemory;
    fn store(&self) -> &Store<Internal> {
        self.memory().store()
    }
    fn store_mut(&mut self) -> &mut Store<Internal> {
        self.memory_mut().store_mut()
    }
    fn internal(&self) -> &Internal {
        self.store().data()
    }
    fn internal_mut(&mut self) -> &mut Internal {
        self.store_mut().data_mut()
    }
}
pub struct Wasi {
    pub ctx: wasmtime_wasi::WasiCtx,
    #[cfg(feature = "nn")]
    pub nn: wasmtime_wasi_nn::WasiNnCtx,
    #[cfg(not(feature = "nn"))]
    pub nn: (),
}
impl Internal {
    pub(crate) fn new(manifest: &Manifest, wasi: bool) -> Result<Self, Error> {
        let wasi = if wasi {
            let auth = wasmtime_wasi::ambient_authority();
            let mut ctx = wasmtime_wasi::WasiCtxBuilder::new();
            for (k, v) in manifest.as_ref().config.iter() {
                ctx = ctx.env(k, v)?;
            }
            if let Some(a) = &manifest.as_ref().allowed_paths {
                for (k, v) in a.iter() {
                    let d = wasmtime_wasi::Dir::open_ambient_dir(k, auth)?;
                    ctx = ctx.preopened_dir(d, v)?;
                }
            }
            #[cfg(feature = "nn")]
            let nn = wasmtime_wasi_nn::WasiNnCtx::new()?;
            #[cfg(not(feature = "nn"))]
            #[allow(clippy::let_unit_value)]
            let nn = ();
            Some(Wasi {
                ctx: ctx.build(),
                nn,
            })
        } else {
            None
        };
        Ok(Internal {
            input_length: 0,
            output_offset: 0,
            output_length: 0,
            input: std::ptr::null(),
            wasi,
            memory: std::ptr::null_mut(),
            http_status: 0,
            last_error: std::cell::RefCell::new(None),
            vars: BTreeMap::new(),
        })
    }
    pub fn set_error(&self, e: impl std::fmt::Debug) {
        debug!("Set error: {:?}", e);
        *self.last_error.borrow_mut() = Some(error_string(e));
    }
    pub fn clear_error(&self) {
        *self.last_error.borrow_mut() = None;
    }
}
impl InternalExt for Internal {
    fn memory(&self) -> &PluginMemory {
        unsafe { &*self.memory }
    }
    fn memory_mut(&mut self) -> &mut PluginMemory {
        unsafe { &mut *self.memory }
    }
}