//! Contract storage abstraction.
//!
//! Provides type-safe access to persistent contract storage.
//!
//! # Example
//!
//! ```rust,ignore
//! use synor_sdk::storage;
//!
//! // Store a simple value
//! storage::set(b"counter", &42u64);
//!
//! // Read it back
//! let counter: u64 = storage::get(b"counter").unwrap_or(0);
//!
//! // Use typed storage slots
//! let balance_slot = storage::Slot::<u64>::new(b"balance");
//! balance_slot.set(&100);
//! let balance = balance_slot.get().unwrap_or(0);
//!
//! // Use maps for per-address data
//! let balances = storage::Map::<Address, u64>::new(b"balances");
//! balances.set(&user_address, &1000);
//! ```

use alloc::vec::Vec;
use borsh::{BorshDeserialize, BorshSerialize};

use crate::host;

/// Computes a storage key from a namespace.
pub fn key_from_bytes(namespace: &[u8]) -> [u8; 32] {
    host::blake3(namespace)
}

/// Computes a compound storage key from namespace and key.
pub fn key_with_suffix(namespace: &[u8], suffix: &[u8]) -> [u8; 32] {
    let mut combined = Vec::with_capacity(namespace.len() + suffix.len());
    combined.extend_from_slice(namespace);
    combined.extend_from_slice(suffix);
    host::blake3(&combined)
}

/// Reads raw bytes from storage.
pub fn get_raw(key: &[u8]) -> Option<Vec<u8>> {
    let storage_key = key_from_bytes(key);
    let mut buffer = [0u8; 4096]; // Max value size
    let len = host::storage_read(&storage_key, &mut buffer);

    if len < 0 {
        None
    } else {
        Some(buffer[..len as usize].to_vec())
    }
}

/// Reads raw bytes with a compound key.
pub fn get_raw_with_suffix(namespace: &[u8], suffix: &[u8]) -> Option<Vec<u8>> {
    let storage_key = key_with_suffix(namespace, suffix);
    let mut buffer = [0u8; 4096];
    let len = host::storage_read(&storage_key, &mut buffer);

    if len < 0 {
        None
    } else {
        Some(buffer[..len as usize].to_vec())
    }
}

/// Writes raw bytes to storage.
pub fn set_raw(key: &[u8], value: &[u8]) {
    let storage_key = key_from_bytes(key);
    host::storage_write(&storage_key, value);
}

/// Writes raw bytes with a compound key.
pub fn set_raw_with_suffix(namespace: &[u8], suffix: &[u8], value: &[u8]) {
    let storage_key = key_with_suffix(namespace, suffix);
    host::storage_write(&storage_key, value);
}

/// Deletes a value from storage.
pub fn delete(key: &[u8]) -> bool {
    let storage_key = key_from_bytes(key);
    host::storage_delete(&storage_key) == 1
}

/// Deletes with a compound key.
pub fn delete_with_suffix(namespace: &[u8], suffix: &[u8]) -> bool {
    let storage_key = key_with_suffix(namespace, suffix);
    host::storage_delete(&storage_key) == 1
}

/// Checks if a key exists.
pub fn exists(key: &[u8]) -> bool {
    get_raw(key).is_some()
}

/// Reads a Borsh-serialized value from storage.
pub fn get<T: BorshDeserialize>(key: &[u8]) -> Option<T> {
    let data = get_raw(key)?;
    T::try_from_slice(&data).ok()
}

/// Reads a Borsh-serialized value with compound key.
pub fn get_with_suffix<T: BorshDeserialize>(namespace: &[u8], suffix: &[u8]) -> Option<T> {
    let data = get_raw_with_suffix(namespace, suffix)?;
    T::try_from_slice(&data).ok()
}

/// Writes a Borsh-serialized value to storage.
pub fn set<T: BorshSerialize>(key: &[u8], value: &T) {
    let data = borsh::to_vec(value).expect("Serialization failed");
    set_raw(key, &data);
}

/// Writes with compound key.
pub fn set_with_suffix<T: BorshSerialize>(namespace: &[u8], suffix: &[u8], value: &T) {
    let data = borsh::to_vec(value).expect("Serialization failed");
    set_raw_with_suffix(namespace, suffix, &data);
}

/// A typed storage slot for a single value.
pub struct Slot<T> {
    key: [u8; 32],
    _marker: core::marker::PhantomData<T>,
}

impl<T: BorshSerialize + BorshDeserialize> Slot<T> {
    /// Creates a new storage slot.
    pub fn new(namespace: &[u8]) -> Self {
        Slot {
            key: key_from_bytes(namespace),
            _marker: core::marker::PhantomData,
        }
    }

    /// Gets the value.
    pub fn get(&self) -> Option<T> {
        let mut buffer = [0u8; 4096];
        let len = host::storage_read(&self.key, &mut buffer);
        if len < 0 {
            None
        } else {
            T::try_from_slice(&buffer[..len as usize]).ok()
        }
    }

    /// Gets the value or a default.
    pub fn get_or_default(&self) -> T
    where
        T: Default,
    {
        self.get().unwrap_or_default()
    }

    /// Sets the value.
    pub fn set(&self, value: &T) {
        let data = borsh::to_vec(value).expect("Serialization failed");
        host::storage_write(&self.key, &data);
    }

    /// Deletes the value.
    pub fn delete(&self) -> bool {
        host::storage_delete(&self.key) == 1
    }

    /// Checks if value exists.
    pub fn exists(&self) -> bool {
        let mut buffer = [0u8; 1];
        host::storage_read(&self.key, &mut buffer) >= 0
    }

    /// Updates the value with a function.
    pub fn update<F>(&self, f: F)
    where
        F: FnOnce(Option<T>) -> Option<T>,
    {
        let current = self.get();
        if let Some(new_value) = f(current) {
            self.set(&new_value);
        } else {
            self.delete();
        }
    }
}

/// A typed storage map (key-value mapping).
pub struct Map<K, V> {
    namespace: [u8; 32],
    _marker: core::marker::PhantomData<(K, V)>,
}

impl<K: AsRef<[u8]>, V: BorshSerialize + BorshDeserialize> Map<K, V> {
    /// Creates a new storage map.
    pub fn new(namespace: &[u8]) -> Self {
        Map {
            namespace: key_from_bytes(namespace),
            _marker: core::marker::PhantomData,
        }
    }

    /// Computes the storage key for a map entry.
    fn entry_key(&self, key: &K) -> [u8; 32] {
        let mut combined = Vec::with_capacity(32 + key.as_ref().len());
        combined.extend_from_slice(&self.namespace);
        combined.extend_from_slice(key.as_ref());
        host::blake3(&combined)
    }

    /// Gets a value by key.
    pub fn get(&self, key: &K) -> Option<V> {
        let storage_key = self.entry_key(key);
        let mut buffer = [0u8; 4096];
        let len = host::storage_read(&storage_key, &mut buffer);
        if len < 0 {
            None
        } else {
            V::try_from_slice(&buffer[..len as usize]).ok()
        }
    }

    /// Gets with default.
    pub fn get_or_default(&self, key: &K) -> V
    where
        V: Default,
    {
        self.get(key).unwrap_or_default()
    }

    /// Sets a value by key.
    pub fn set(&self, key: &K, value: &V) {
        let storage_key = self.entry_key(key);
        let data = borsh::to_vec(value).expect("Serialization failed");
        host::storage_write(&storage_key, &data);
    }

    /// Deletes a value by key.
    pub fn delete(&self, key: &K) -> bool {
        let storage_key = self.entry_key(key);
        host::storage_delete(&storage_key) == 1
    }

    /// Checks if key exists.
    pub fn contains(&self, key: &K) -> bool {
        let storage_key = self.entry_key(key);
        let mut buffer = [0u8; 1];
        host::storage_read(&storage_key, &mut buffer) >= 0
    }

    /// Updates a value with a function.
    pub fn update<F>(&self, key: &K, f: F)
    where
        F: FnOnce(Option<V>) -> Option<V>,
    {
        let current = self.get(key);
        if let Some(new_value) = f(current) {
            self.set(key, &new_value);
        } else {
            self.delete(key);
        }
    }
}

/// A typed set (just keys, no values).
pub struct Set<K> {
    map: Map<K, bool>,
}

impl<K: AsRef<[u8]>> Set<K> {
    /// Creates a new storage set.
    pub fn new(namespace: &[u8]) -> Self {
        Set {
            map: Map::new(namespace),
        }
    }

    /// Adds a key to the set.
    pub fn insert(&self, key: &K) {
        self.map.set(key, &true);
    }

    /// Removes a key from the set.
    pub fn remove(&self, key: &K) -> bool {
        self.map.delete(key)
    }

    /// Checks if key exists.
    pub fn contains(&self, key: &K) -> bool {
        self.map.contains(key)
    }
}

/// Counter storage utility.
pub struct Counter {
    slot: Slot<u64>,
}

impl Counter {
    /// Creates a new counter.
    pub fn new(namespace: &[u8]) -> Self {
        Counter {
            slot: Slot::new(namespace),
        }
    }

    /// Gets the current value.
    pub fn get(&self) -> u64 {
        self.slot.get_or_default()
    }

    /// Increments and returns the new value.
    pub fn increment(&self) -> u64 {
        let value = self.get() + 1;
        self.slot.set(&value);
        value
    }

    /// Decrements and returns the new value (saturating at 0).
    pub fn decrement(&self) -> u64 {
        let value = self.get().saturating_sub(1);
        self.slot.set(&value);
        value
    }

    /// Adds to the counter.
    pub fn add(&self, amount: u64) -> u64 {
        let value = self.get().saturating_add(amount);
        self.slot.set(&value);
        value
    }

    /// Subtracts from the counter (saturating at 0).
    pub fn sub(&self, amount: u64) -> u64 {
        let value = self.get().saturating_sub(amount);
        self.slot.set(&value);
        value
    }

    /// Sets the counter value.
    pub fn set(&self, value: u64) {
        self.slot.set(&value);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_key_computation() {
        let key1 = key_from_bytes(b"test");
        let key2 = key_from_bytes(b"test");
        let key3 = key_from_bytes(b"other");

        assert_eq!(key1, key2);
        assert_ne!(key1, key3);
    }

    #[test]
    fn test_compound_key() {
        let key1 = key_with_suffix(b"map", b"key1");
        let key2 = key_with_suffix(b"map", b"key2");
        let key3 = key_with_suffix(b"other_map", b"key1");

        assert_ne!(key1, key2);
        assert_ne!(key1, key3);
    }
}
