// src/store.rs
use std::any::{type_name, Any, TypeId};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use crate::any_value::AnyValue;
use crate::error::MapError;

/// A thread-safe container that stores exactly one value per type.
///
/// `TypeStore` provides a simple way to store and retrieve values using their
/// type as the key. This is useful for dependency injection, service locators,
/// and managing application-wide state without explicit key management.
///
/// Unlike `TypeMap` which uses explicit keys, `TypeStore` uses the type itself
/// as the key, meaning you can only store one value of each type.
///
/// # Examples
///
/// ```
/// use sovran_typemap::{TypeStore, MapError};
///
/// #[derive(Clone, Debug)]
/// struct DatabaseConfig {
///     host: String,
///     port: u16,
/// }
///
/// #[derive(Clone, Debug)]
/// struct AppConfig {
///     name: String,
///     debug: bool,
/// }
///
/// fn main() -> Result<(), MapError> {
///     let store = TypeStore::new();
///
///     // Store configurations by type
///     store.set(DatabaseConfig {
///         host: "localhost".to_string(),
///         port: 5432,
///     })?;
///
///     store.set(AppConfig {
///         name: "MyApp".to_string(),
///         debug: true,
///     })?;
///
///     // Retrieve by type - no key needed
///     let db_config = store.get::<DatabaseConfig>()?;
///     println!("Database: {}:{}", db_config.host, db_config.port);
///
///     // Modify in place
///     store.with_mut::<AppConfig, _, _>(|cfg| {
///         cfg.debug = false;
///     })?;
///
///     Ok(())
/// }
/// ```
#[derive(Clone, Debug)]
pub struct TypeStore {
    items: Arc<Mutex<HashMap<TypeId, AnyValue>>>,
}

impl TypeStore {
    /// Creates a new, empty TypeStore.
    ///
    /// # Examples
    ///
    /// ```
    /// use sovran_typemap::TypeStore;
    ///
    /// let store = TypeStore::new();
    /// ```
    pub fn new() -> Self {
        Self {
            items: Arc::new(Mutex::new(HashMap::new())),
        }
    }

    /// Stores a value, using its type as the key.
    ///
    /// If a value of this type already exists, it will be replaced.
    ///
    /// # Errors
    ///
    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeStore, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store = TypeStore::new();
    ///
    /// store.set(42i32)?;
    /// store.set("hello".to_string())?;
    /// store.set(vec![1, 2, 3])?;
    ///
    /// // Overwrites the previous i32
    /// store.set(100i32)?;
    /// assert_eq!(store.get::<i32>()?, 100);
    /// # Ok(())
    /// # }
    /// ```
    pub fn set<V>(&self, value: V) -> Result<(), MapError>
    where
        V: 'static + Any + Send + Sync,
    {
        let mut store = self.items.lock().map_err(|_| MapError::LockError)?;
        store.insert(TypeId::of::<V>(), AnyValue::new(value));
        Ok(())
    }

    /// Stores a value generated by a closure.
    ///
    /// This is useful for lazy initialization or when value construction
    /// should only happen if the lock can be acquired.
    ///
    /// # Errors
    ///
    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeStore, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store = TypeStore::new();
    ///
    /// // Lazily construct a value
    /// store.set_with(|| {
    ///     vec![1, 2, 3, 4, 5]
    /// })?;
    ///
    /// store.with::<Vec<i32>, _, _>(|v| {
    ///     assert_eq!(v.len(), 5);
    /// })?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn set_with<V, F>(&self, f: F) -> Result<(), MapError>
    where
        V: 'static + Any + Send + Sync,
        F: FnOnce() -> V,
    {
        let value = f();
        self.set(value)
    }

    /// Retrieves a clone of a value by its type.
    ///
    /// # Errors
    ///
    /// - Returns `MapError::LockError` if the internal lock cannot be acquired
    /// - Returns `MapError::KeyNotFound` if no value of this type exists
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeStore, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store = TypeStore::new();
    /// store.set(42i32)?;
    ///
    /// let value = store.get::<i32>()?;
    /// assert_eq!(value, 42);
    ///
    /// // Type not found
    /// match store.get::<String>() {
    ///     Err(MapError::KeyNotFound(type_name)) => {
    ///         println!("No value of type: {}", type_name);
    ///     }
    ///     _ => {}
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub fn get<V>(&self) -> Result<V, MapError>
    where
        V: 'static + Clone,
    {
        self.with(|val: &V| val.clone())
    }

    /// Accesses a value by type with a read-only closure.
    ///
    /// # Errors
    ///
    /// - Returns `MapError::LockError` if the internal lock cannot be acquired
    /// - Returns `MapError::KeyNotFound` if no value of this type exists
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeStore, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store = TypeStore::new();
    /// store.set(vec![1, 2, 3, 4, 5])?;
    ///
    /// let sum = store.with::<Vec<i32>, _, _>(|numbers| {
    ///     numbers.iter().sum::<i32>()
    /// })?;
    /// assert_eq!(sum, 15);
    /// # Ok(())
    /// # }
    /// ```
    pub fn with<V: 'static, F, R>(&self, f: F) -> Result<R, MapError>
    where
        F: FnOnce(&V) -> R,
    {
        let guard = self.items.lock().map_err(|_| MapError::LockError)?;
        let value = guard
            .get(&TypeId::of::<V>())
            .ok_or_else(|| MapError::KeyNotFound(type_name::<V>().to_string()))?;

        // Type is guaranteed to match since TypeId is the key
        let reference = value.downcast_ref::<V>().unwrap();
        Ok(f(reference))
    }

    /// Accesses a value by type with a read-write closure.
    ///
    /// # Errors
    ///
    /// - Returns `MapError::LockError` if the internal lock cannot be acquired
    /// - Returns `MapError::KeyNotFound` if no value of this type exists
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeStore, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store = TypeStore::new();
    /// store.set(vec![1, 2, 3])?;
    ///
    /// store.with_mut::<Vec<i32>, _, _>(|numbers| {
    ///     numbers.push(4);
    ///     numbers.push(5);
    /// })?;
    ///
    /// let len = store.with::<Vec<i32>, _, _>(|v| v.len())?;
    /// assert_eq!(len, 5);
    /// # Ok(())
    /// # }
    /// ```
    pub fn with_mut<V: 'static, F, R>(&self, f: F) -> Result<R, MapError>
    where
        F: FnOnce(&mut V) -> R,
    {
        let mut guard = self.items.lock().map_err(|_| MapError::LockError)?;
        let value = guard
            .get_mut(&TypeId::of::<V>())
            .ok_or_else(|| MapError::KeyNotFound(type_name::<V>().to_string()))?;

        // Type is guaranteed to match since TypeId is the key
        let reference = value.downcast_mut::<V>().unwrap();
        Ok(f(reference))
    }

    /// Removes a value by its type.
    ///
    /// # Errors
    ///
    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
    ///
    /// # Returns
    ///
    /// Returns `Ok(true)` if a value was removed, `Ok(false)` if no value
    /// of that type existed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeStore, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store = TypeStore::new();
    /// store.set(42i32)?;
    ///
    /// assert!(store.remove::<i32>()?);
    /// assert!(!store.remove::<i32>()?); // Already removed
    /// # Ok(())
    /// # }
    /// ```
    pub fn remove<V: 'static>(&self) -> Result<bool, MapError> {
        let mut store = self.items.lock().map_err(|_| MapError::LockError)?;
        Ok(store.remove(&TypeId::of::<V>()).is_some())
    }

    /// Checks if a value of the given type exists.
    ///
    /// # Errors
    ///
    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeStore, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store = TypeStore::new();
    ///
    /// assert!(!store.contains::<i32>()?);
    /// store.set(42i32)?;
    /// assert!(store.contains::<i32>()?);
    /// # Ok(())
    /// # }
    /// ```
    pub fn contains<V: 'static>(&self) -> Result<bool, MapError> {
        let store = self.items.lock().map_err(|_| MapError::LockError)?;
        Ok(store.contains_key(&TypeId::of::<V>()))
    }

    /// Gets the number of values in the store.
    ///
    /// # Errors
    ///
    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeStore, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store = TypeStore::new();
    /// assert_eq!(store.len()?, 0);
    ///
    /// store.set(42i32)?;
    /// store.set("hello".to_string())?;
    /// assert_eq!(store.len()?, 2);
    /// # Ok(())
    /// # }
    /// ```
    pub fn len(&self) -> Result<usize, MapError> {
        let store = self.items.lock().map_err(|_| MapError::LockError)?;
        Ok(store.len())
    }

    /// Checks if the store is empty.
    ///
    /// # Errors
    ///
    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeStore, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store = TypeStore::new();
    /// assert!(store.is_empty()?);
    ///
    /// store.set(42i32)?;
    /// assert!(!store.is_empty()?);
    /// # Ok(())
    /// # }
    /// ```
    pub fn is_empty(&self) -> Result<bool, MapError> {
        let store = self.items.lock().map_err(|_| MapError::LockError)?;
        Ok(store.is_empty())
    }
}

impl Default for TypeStore {
    fn default() -> Self {
        Self::new()
    }
}

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

    #[derive(Clone, Debug, PartialEq)]
    struct TestConfig {
        name: String,
        value: i32,
    }

    #[derive(Clone, Debug, PartialEq)]
    struct AnotherConfig {
        enabled: bool,
    }

    #[test]
    fn test_set_and_get() -> Result<(), MapError> {
        let store = TypeStore::new();

        store.set(TestConfig {
            name: "test".to_string(),
            value: 42,
        })?;

        let config = store.get::<TestConfig>()?;
        assert_eq!(config.name, "test");
        assert_eq!(config.value, 42);

        Ok(())
    }

    #[test]
    fn test_multiple_types() -> Result<(), MapError> {
        let store = TypeStore::new();

        store.set(TestConfig {
            name: "test".to_string(),
            value: 42,
        })?;
        store.set(AnotherConfig { enabled: true })?;
        store.set(123i32)?;
        store.set("hello".to_string())?;

        assert_eq!(store.get::<TestConfig>()?.value, 42);
        assert!(store.get::<AnotherConfig>()?.enabled);
        assert_eq!(store.get::<i32>()?, 123);
        assert_eq!(store.get::<String>()?, "hello");

        Ok(())
    }

    #[test]
    fn test_overwrite() -> Result<(), MapError> {
        let store = TypeStore::new();

        store.set(42i32)?;
        assert_eq!(store.get::<i32>()?, 42);

        store.set(100i32)?;
        assert_eq!(store.get::<i32>()?, 100);

        // Still only one item
        assert_eq!(store.len()?, 1);

        Ok(())
    }

    #[test]
    fn test_with() -> Result<(), MapError> {
        let store = TypeStore::new();
        store.set(vec![1, 2, 3, 4, 5])?;

        let sum = store.with::<Vec<i32>, _, _>(|v| v.iter().sum::<i32>())?;
        assert_eq!(sum, 15);

        Ok(())
    }

    #[test]
    fn test_with_mut() -> Result<(), MapError> {
        let store = TypeStore::new();
        store.set(vec![1, 2, 3])?;

        store.with_mut::<Vec<i32>, _, _>(|v| {
            v.push(4);
            v.push(5);
        })?;

        let len = store.with::<Vec<i32>, _, _>(|v| v.len())?;
        assert_eq!(len, 5);

        Ok(())
    }

    #[test]
    fn test_remove() -> Result<(), MapError> {
        let store = TypeStore::new();
        store.set(42i32)?;

        assert!(store.contains::<i32>()?);
        assert!(store.remove::<i32>()?);
        assert!(!store.contains::<i32>()?);
        assert!(!store.remove::<i32>()?);

        Ok(())
    }

    #[test]
    fn test_contains() -> Result<(), MapError> {
        let store = TypeStore::new();

        assert!(!store.contains::<i32>()?);
        store.set(42i32)?;
        assert!(store.contains::<i32>()?);

        Ok(())
    }

    #[test]
    fn test_len_and_is_empty() -> Result<(), MapError> {
        let store = TypeStore::new();

        assert!(store.is_empty()?);
        assert_eq!(store.len()?, 0);

        store.set(42i32)?;
        assert!(!store.is_empty()?);
        assert_eq!(store.len()?, 1);

        store.set("hello".to_string())?;
        assert_eq!(store.len()?, 2);

        store.remove::<i32>()?;
        assert_eq!(store.len()?, 1);

        Ok(())
    }

    #[test]
    fn test_key_not_found_error() {
        let store = TypeStore::new();

        match store.get::<TestConfig>() {
            Err(MapError::KeyNotFound(type_name)) => {
                assert!(type_name.contains("TestConfig"));
            }
            _ => panic!("Expected KeyNotFound error"),
        }
    }

    #[test]
    fn test_set_with() -> Result<(), MapError> {
        let store = TypeStore::new();

        store.set_with(|| TestConfig {
            name: "lazy".to_string(),
            value: 99,
        })?;

        let config = store.get::<TestConfig>()?;
        assert_eq!(config.name, "lazy");
        assert_eq!(config.value, 99);

        Ok(())
    }

    #[test]
    fn test_thread_safety() -> Result<(), MapError> {
        use std::sync::Arc;
        use std::thread;

        let store = Arc::new(TypeStore::new());
        store.set(0i32)?;

        let mut handles = vec![];

        for _ in 0..10 {
            let store = Arc::clone(&store);
            handles.push(thread::spawn(move || {
                for _ in 0..100 {
                    store
                        .with_mut::<i32, _, _>(|v| {
                            *v += 1;
                        })
                        .unwrap();
                }
            }));
        }

        for handle in handles {
            handle.join().unwrap();
        }

        assert_eq!(store.get::<i32>()?, 1000);

        Ok(())
    }
}
