use std::any::Any;
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::sync::{Arc, Mutex};

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

/// A thread-safe heterogeneous container with type-safety
///
/// `TypeMap` allows you to store values of different types in a single container
/// while maintaining type-safety through runtime checks. It provides a convenient way
/// to share state between components without requiring all components to know about all types.
///
/// # Examples
///
/// ```
/// use sovran_typemap::{TypeMap, MapError};
///
/// fn main() -> Result<(), MapError> {
///     // Create a new TypeMap with string keys
///     let store = TypeMap::<String>::new();
///
///     // Store values of different types
///     store.set("number".to_string(), 42i32)?;
///     store.set("text".to_string(), "Hello, world!".to_string())?;
///     store.set("flags".to_string(), vec![true, false, true])?;
///
///     // Retrieve values with type safety
///     let num = store.get::<i32>(&"number".to_string())?;
///     println!("Retrieved: {}", num);
///
///     // Use with_mut to modify values in place
///     store.with_mut::<Vec<bool>, _, _>(&"flags".to_string(), |flags| {
///         flags.push(true);
///         println!("Updated flags: {:?}", flags);
///     })?;
///
///     Ok(())
/// }
/// ```
#[derive(Clone, Debug)]
pub struct TypeMap<K> {
    pub(crate) items: Arc<Mutex<HashMap<K, AnyValue>>>,
}

impl<K> TypeMap<K>
where
    K: Clone + Eq + Hash + Debug,
{
    /// Creates a new, empty TypeMap
    ///
    /// # Examples
    ///
    /// ```
    /// use sovran_typemap::TypeMap;
    ///
    /// // Create a TypeMap with String keys
    /// let string_store = TypeMap::<String>::new();
    ///
    /// // Create a TypeMap with numeric keys
    /// let int_store = TypeMap::<u32>::new();
    /// ```
    pub fn new() -> Self {
        Self {
            items: Arc::new(Mutex::new(HashMap::new())),
        }
    }

    /// Stores a value of any type that implements Any, Send, and Sync
    ///
    /// # Errors
    ///
    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeMap, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store: TypeMap<String> = TypeMap::new();
    ///
    /// // Store values of different types
    /// store.set("number".to_string(), 42i32)?;
    /// store.set("text".to_string(), "Hello, world!".to_string())?;
    /// store.set("complex".to_string(), (1, "tuple", true))?;
    ///
    /// // Overwrite an existing value
    /// store.set("number".to_string(), 100i32)?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn set<V>(&self, key: K, value: V) -> Result<(), MapError>
    where
        V: 'static + Any + Send + Sync,
    {
        let mut store = self.items.lock().map_err(|_| MapError::LockError)?;
        store.insert(key, AnyValue::new(value));
        Ok(())
    }

    /// Stores a value generated by a closure
    ///
    /// This is useful for lazy initialization or complex value construction where
    /// you want to avoid creating the value if the lock can't be acquired.
    ///
    /// # Errors
    ///
    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeMap, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store: TypeMap<String> = TypeMap::new();
    ///
    /// // Lazily construct a complex value
    /// store.set_with("user_data".to_string(), || {
    ///     // Imagine this is an expensive operation
    ///     let mut data = Vec::new();
    ///     for i in 0..1000 {
    ///         data.push(i * 2);
    ///     }
    ///     data
    /// })?;
    ///
    /// // Access the constructed data
    /// store.with(&"user_data".to_string(), |data: &Vec<i32>| {
    ///     println!("First value: {}", data.first().unwrap_or(&0));
    /// })?;
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// Handling potential errors:
    ///
    /// ```
    /// # use sovran_typemap::{TypeMap, MapError};
    /// # fn main() {
    /// let store: TypeMap<String> = TypeMap::new();
    ///
    /// // Handle potential errors from set_with
    /// match store.set_with("config".to_string(), || {
    ///     // In a real scenario, this might load from a file
    ///     std::collections::HashMap::<String, String>::new()
    /// }) {
    ///     Ok(()) => println!("Configuration stored successfully"),
    ///     Err(MapError::LockError) => eprintln!("Failed to acquire lock - try again later"),
    ///     Err(e) => eprintln!("Unexpected error: {}", e),
    /// }
    /// # }
    /// ```
    pub fn set_with<V, F>(&self, key: K, f: F) -> Result<(), MapError>
    where
        V: 'static + Any + Send + Sync,
        F: FnOnce() -> V,
    {
        let value = f();
        self.set(key, value)
    }

    /// Retrieves a clone of a value from the store
    ///
    /// This provides a convenient way to get a copy of a value when the `Clone`
    /// trait is available. For more complex operations or to avoid cloning,
    /// use `with` instead.
    ///
    /// # Type Parameters
    ///
    /// * `V` - The type of the value to retrieve. Must match the type that was stored.
    ///
    /// # Errors
    ///
    /// - Returns `MapError::LockError` if the internal lock cannot be acquired
    /// - Returns `MapError::KeyNotFound` if the key doesn't exist in the store
    /// - Returns `MapError::TypeMismatch` if the value exists but has a different type
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeMap, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store: TypeMap<String> = TypeMap::new();
    /// store.set("answer".to_string(), 42i32)?;
    ///
    /// // Get a clone of the value
    /// let value = store.get::<i32>(&"answer".to_string())?;
    /// assert_eq!(value, 42);
    ///
    /// // Handle possible errors
    /// match store.get::<String>(&"non_existent".to_string()) {
    ///     Ok(value) => println!("Value: {}", value),
    ///     Err(MapError::KeyNotFound(key)) => println!("Key not found {}", key),
    ///     Err(MapError::TypeMismatch) => println!("Type mismatch"),
    ///     Err(MapError::LockError) => println!("Failed to acquire lock"),
    /// }
    ///
    /// // Type mismatch example
    /// store.set("name".to_string(), "Alice".to_string())?;
    /// match store.get::<i32>(&"name".to_string()) {
    ///     Ok(value) => println!("Value: {}", value),
    ///     Err(MapError::TypeMismatch) => println!("The value is not an i32"),
    ///     Err(e) => println!("Other error: {}", e),
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub fn get<V>(&self, key: &K) -> Result<V, MapError>
    where
        V: 'static + Clone,
    {
        self.with(key, |val: &V| val.clone())
    }

    /// Gets a value by executing a closure with read access
    ///
    /// This method allows for arbitrary operations on the stored value without
    /// requiring the value to implement `Clone`. It's useful for inspecting values,
    /// computing derived values, or performing operations that don't require ownership.
    ///
    /// # Type Parameters
    ///
    /// * `V` - The type of the value to access. Must match the type that was stored.
    /// * `F` - A closure that takes a reference to the value and returns a result.
    /// * `R` - The return type of the closure.
    ///
    /// # Errors
    ///
    /// - Returns `MapError::LockError` if the internal lock cannot be acquired
    /// - Returns `MapError::KeyNotFound` if the key doesn't exist in the store
    /// - Returns `MapError::TypeMismatch` if the value exists but has a different type
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeMap, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store: TypeMap<String> = TypeMap::new();
    /// store.set("users".to_string(), vec!["Alice", "Bob", "Charlie"])?;
    ///
    /// // Read and compute something from the value
    /// let user_count = store.with(&"users".to_string(), |users: &Vec<&str>| users.len())?;
    /// println!("Number of users: {}", user_count);
    ///
    /// // Checking if a specific value exists
    /// let has_alice = store.with(&"users".to_string(), |users: &Vec<&str>| {
    ///     users.contains(&"Alice")
    /// })?;
    ///
    /// // Handle potential errors with pattern matching
    /// match store.with(&"settings".to_string(), |settings: &std::collections::HashMap<String, String>| {
    ///     settings.get("theme").cloned()
    /// }) {
    ///     Ok(Some(theme)) => println!("Current theme: {}", theme),
    ///     Ok(None) => println!("Theme setting not found"),
    ///     Err(MapError::KeyNotFound(_)) => println!("Settings not initialized"),
    ///     Err(MapError::TypeMismatch) => println!("Settings has unexpected type"),
    ///     Err(e) => println!("Error: {}", e),
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub fn with<V: 'static, F, R>(&self, key: &K, f: F) -> Result<R, MapError>
    where
        F: FnOnce(&V) -> R,
    {
        let guard = self.items.lock().map_err(|_| MapError::LockError)?;
        let value = guard
            .get(key)
            .ok_or_else(|| MapError::KeyNotFound(format!("{:?}", key)))?;

        if !value.is_type::<V>() {
            return Err(MapError::TypeMismatch);
        }

        // This is safe because we've checked the type
        let reference = value.downcast_ref::<V>().unwrap();
        Ok(f(reference))
    }

    /// Gets a value by executing a closure with write access
    ///
    /// This method allows for modifying the stored value in place without
    /// replacing it entirely. It's useful for updating collections or
    /// complex structures.
    ///
    /// # Type Parameters
    ///
    /// * `V` - The type of the value to access. Must match the type that was stored.
    /// * `F` - A closure that takes a mutable reference to the value and returns a result.
    /// * `R` - The return type of the closure.
    ///
    /// # Errors
    ///
    /// - Returns `MapError::LockError` if the internal lock cannot be acquired
    /// - Returns `MapError::KeyNotFound` if the key doesn't exist in the store
    /// - Returns `MapError::TypeMismatch` if the value exists but has a different type
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeMap, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store: TypeMap<String> = TypeMap::new();
    ///
    /// // Initialize a vector
    /// store.set("numbers".to_string(), vec![1, 2, 3])?;
    ///
    /// // Modify the vector in place
    /// store.with_mut(&"numbers".to_string(), |numbers: &mut Vec<i32>| {
    ///     numbers.push(4);
    ///     numbers.push(5);
    /// })?;
    ///
    /// // Verify the modification
    /// let count = store.with(&"numbers".to_string(), |numbers: &Vec<i32>| {
    ///     assert_eq!(numbers, &[1, 2, 3, 4, 5]);
    ///     numbers.len()
    /// })?;
    /// println!("Vector now has {} elements", count);
    ///
    /// // Example with a HashMap
    /// store.set("counters".to_string(), std::collections::HashMap::<String, i32>::new())?;
    ///
    /// // Update counter values
    /// let result = store.with_mut(&"counters".to_string(), |counters: &mut std::collections::HashMap<String, i32>| {
    ///     *counters.entry("visits".to_string()).or_insert(0) += 1;
    ///     counters.get("visits").copied() // Return current count
    /// })?;
    /// println!("Visit count: {}", result.unwrap_or(0));
    ///
    /// // Error handling example
    /// match store.with_mut(&"config".to_string(), |config: &mut std::collections::HashMap<String, String>| {
    ///     config.insert("theme".to_string(), "dark".to_string())
    /// }) {
    ///     Ok(old_theme) => println!("Previous theme: {:?}", old_theme),
    ///     Err(MapError::KeyNotFound(_)) => println!("Config not found"),
    ///     Err(MapError::TypeMismatch) => println!("Config has wrong type"),
    ///     Err(e) => println!("Error: {}", e),
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub fn with_mut<V: 'static, F, R>(&self, key: &K, 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(key)
            .ok_or_else(|| MapError::KeyNotFound(format!("{:?}", key)))?;

        if !value.is_type::<V>() {
            return Err(MapError::TypeMismatch);
        }

        // This is safe because we've checked the type
        let reference = value.downcast_mut::<V>().unwrap();
        Ok(f(reference))
    }

    /// Removes a value from the store
    ///
    /// # Errors
    ///
    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
    ///
    /// # Returns
    ///
    /// Returns `Ok(true)` if the key was present and the value was removed.
    /// Returns `Ok(false)` if the key was not present.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeMap, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store: TypeMap<String> = TypeMap::new();
    /// store.set("temp".to_string(), "This is temporary".to_string())?;
    ///
    /// // Remove the value
    /// let was_removed = store.remove(&"temp".to_string())?;
    /// assert!(was_removed);
    ///
    /// // Check that it's gone
    /// match store.get::<String>(&"temp".to_string()) {
    ///     Err(MapError::KeyNotFound(key)) => println!("Key `{}` was successfully removed", key),
    ///     Ok(_) => println!("Key still exists"),
    ///     Err(e) => println!("Error: {}", e),
    /// }
    ///
    /// // Removing a non-existent key
    /// let was_removed = store.remove(&"nonexistent".to_string())?;
    /// assert!(!was_removed);
    ///
    /// // Using pattern matching for error handling
    /// match store.remove(&"another_key".to_string()) {
    ///     Ok(true) => println!("Key was found and removed"),
    ///     Ok(false) => println!("Key did not exist"),
    ///     Err(MapError::LockError) => println!("Failed to acquire lock"),
    ///     Err(e) => println!("Unexpected error: {}", e),
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub fn remove(&self, key: &K) -> Result<bool, MapError> {
        let mut store = self.items.lock().map_err(|_| MapError::LockError)?;
        Ok(store.remove(key).is_some())
    }

    /// Checks if a key exists in the store
    ///
    /// This method only checks for the existence of the key and does not validate
    /// the type of the stored value.
    ///
    /// # Errors
    ///
    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeMap, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store: TypeMap<String> = TypeMap::new();
    /// store.set("config".to_string(), std::collections::HashMap::<String, String>::new())?;
    ///
    /// // Check if a key exists
    /// let has_config = store.contains_key(&"config".to_string())?;
    /// assert!(has_config);
    ///
    /// let has_users = store.contains_key(&"users".to_string())?;
    /// assert!(!has_users);
    ///
    /// // Use in conditional logic
    /// if !store.contains_key(&"initialized".to_string())? {
    ///     store.set("initialized".to_string(), true)?;
    ///     println!("Store initialized for the first time");
    /// }
    ///
    /// // Error handling
    /// match store.contains_key(&"settings".to_string()) {
    ///     Ok(true) => println!("Settings exist"),
    ///     Ok(false) => println!("Settings do not exist"),
    ///     Err(e) => println!("Error checking settings: {}", e),
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub fn contains_key(&self, key: &K) -> Result<bool, MapError> {
        let store = self.items.lock().map_err(|_| MapError::LockError)?;
        Ok(store.contains_key(key))
    }

    /// Gets all keys in the store
    ///
    /// # Errors
    ///
    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeMap, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store: TypeMap<String> = TypeMap::new();
    /// store.set("user".to_string(), "Alice".to_string())?;
    /// store.set("count".to_string(), 42i32)?;
    /// store.set("active".to_string(), true)?;
    ///
    /// // Get all keys
    /// let keys = store.keys()?;
    ///
    /// // Keys are returned in arbitrary order, so sort for stable testing
    /// let mut sorted_keys = keys.clone();
    /// sorted_keys.sort();
    ///
    /// assert_eq!(sorted_keys, vec!["active".to_string(), "count".to_string(), "user".to_string()]);
    /// println!("Store contains {} keys", keys.len());
    ///
    /// // Use keys to iterate over stored values
    /// for key in keys {
    ///     // We need to handle different types differently
    ///     if let Ok(value) = store.get::<String>(&key) {
    ///         println!("{}: String = {}", key, value);
    ///     } else if let Ok(value) = store.get::<i32>(&key) {
    ///         println!("{}: i32 = {}", key, value);
    ///     } else if let Ok(value) = store.get::<bool>(&key) {
    ///         println!("{}: bool = {}", key, value);
    ///     } else {
    ///         println!("{}: unknown type", key);
    ///     }
    /// }
    ///
    /// // Error handling
    /// match store.keys() {
    ///     Ok(keys) => println!("Found {} keys", keys.len()),
    ///     Err(MapError::LockError) => println!("Failed to acquire lock"),
    ///     Err(e) => println!("Unexpected error: {}", e),
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub fn keys(&self) -> Result<Vec<K>, MapError>
    where
        K: Clone,
    {
        let store = self.items.lock().map_err(|_| MapError::LockError)?;
        Ok(store.keys().cloned().collect())
    }

    pub fn values<V>(&self) -> Result<Vec<V>, MapError>
    where
        V: 'static + Clone,
    {
        let store = self.items.lock().map_err(|_| MapError::LockError)?;
        let mut result = Vec::new();

        for value in store.values() {
            if value.is_type::<V>() {
                // This is safe because we've checked the type
                if let Some(v) = value.downcast_ref::<V>() {
                    result.push(v.clone());
                }
            }
        }

        Ok(result)
    }

    /// Gets the number of items in the store
    ///
    /// # Errors
    ///
    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sovran_typemap::{TypeMap, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store: TypeMap<String> = TypeMap::new();
    ///
    /// // Initially empty
    /// assert_eq!(store.len()?, 0);
    ///
    /// // Add some items
    /// store.set("one".to_string(), 1)?;
    /// store.set("two".to_string(), 2)?;
    ///
    /// // Check the count
    /// assert_eq!(store.len()?, 2);
    ///
    /// // Use in conditional logic
    /// if store.len()? > 10 {
    ///     println!("Store has many items");
    /// } else {
    ///     println!("Store has few items");
    /// }
    ///
    /// // Error handling
    /// match store.len() {
    ///     Ok(count) => println!("Store contains {} items", count),
    ///     Err(MapError::LockError) => println!("Failed to acquire lock"),
    ///     Err(e) => println!("Unexpected error: {}", e),
    /// }
    /// # 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::{TypeMap, MapError};
    /// # fn main() -> Result<(), MapError> {
    /// let store: TypeMap<String> = TypeMap::new();
    ///
    /// // New store is empty
    /// assert!(store.is_empty()?);
    ///
    /// // Add an item
    /// store.set("key".to_string(), "value".to_string())?;
    ///
    /// // Now it's not empty
    /// assert!(!store.is_empty()?);
    ///
    /// // Use in conditional logic
    /// if store.is_empty()? {
    ///     println!("Store is empty");
    /// } else {
    ///     println!("Store contains items");
    /// }
    ///
    /// // Error handling
    /// match store.is_empty() {
    ///     Ok(true) => println!("Store is empty"),
    ///     Ok(false) => println!("Store has items"),
    ///     Err(MapError::LockError) => println!("Failed to acquire lock"),
    ///     Err(e) => println!("Unexpected error: {}", e),
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub fn is_empty(&self) -> Result<bool, MapError> {
        let store = self.items.lock().map_err(|_| MapError::LockError)?;
        Ok(store.is_empty())
    }
}

impl<K> Default for TypeMap<K>
where
    K: Clone + Eq + Hash + Debug,
{
    fn default() -> Self {
        Self::new()
    }
}
