//! Types related to getting and setting values in local storage.

use crate::ComponentImports;

/// An error when attempting to retrieve an value from local storage.
#[derive(Debug)]
pub enum LocalStorageGetItemError {
    /// The key was too long.
    KeyTooLong,
    /// The key's bytes were not valid UTF-8.
    KeyNotUtf8,
    /// The out buffer was smaller than the length of the input element's value.
    OutBufferBelowMinimumSize,
    /// The out buffer was smaller than the length of the local storage item's value.
    #[allow(missing_docs)]
    OutBufferSmallerThanValue { value_len: usize },
    #[allow(missing_docs)]
    Unrecognized { error_code: i32 },
}

impl ComponentImports {
    /// Get an item from local storage.
    pub fn local_storage_get_item<'out>(
        &self,
        key: &str,
        out_buffer: &'out mut [u8],
    ) -> Result<Option<&'out str>, LocalStorageGetItemError> {
        let returned = unsafe {
            afia_component_sys::local_storage_get_item(
                self.component_imports_ptr,
                key.as_ptr(),
                key.len(),
                out_buffer.as_mut_ptr(),
                out_buffer.len(),
            )
        };

        match returned {
            length if length >= 0 => {
                let length = length as usize;

                // SAFETY: here we are trusting that the Afia host worked as expected and wrote a
                // utf8 string to the buffer.
                let string = unsafe { std::str::from_utf8_unchecked(&out_buffer[0..length]) };

                Ok(Some(string))
            }
            -1 => Err(LocalStorageGetItemError::KeyTooLong),
            -2 => Err(LocalStorageGetItemError::KeyNotUtf8),
            -3 => Ok(None),
            -4 => Err(LocalStorageGetItemError::OutBufferBelowMinimumSize),
            -5 => {
                let mut val_len = [0; 4];
                val_len.copy_from_slice(&out_buffer[0..4]);
                let val = i32::from_le_bytes(val_len);
                Err(LocalStorageGetItemError::OutBufferSmallerThanValue {
                    value_len: val as usize,
                })
            }
            unknown_error_code => Err(LocalStorageGetItemError::Unrecognized {
                error_code: unknown_error_code,
            }),
        }
    }

    /// Set an item in local storage.
    pub fn local_storage_set_item(&self, key: &str, val: &str) {
        unsafe {
            afia_component_sys::local_storage_set_item(
                self.component_imports_ptr,
                key.as_ptr(),
                key.len(),
                val.as_ptr(),
                val.len(),
            )
        }
    }
}
