//! Cache management for category metadata
//!
//! Handles loading and caching of meta configurations from TOML/JSON files

use std::collections::HashMap;
use std::path::Path;
use std::sync::{LazyLock, RwLock};

use serde::Deserialize;

#[derive(Debug, Clone, Deserialize, serde::Serialize)]
pub struct MetaConfig {
    pub categories_emojis: HashMap<String, String>,
    #[serde(default)]
    pub tags_emojis: HashMap<String, String>,
}

/// Cache for meta configurations to avoid repeated file reads
pub(crate) static META_CACHE: LazyLock<RwLock<HashMap<String, MetaConfig>>> =
    LazyLock::new(|| RwLock::new(HashMap::new()));

/// Load meta configuration from TOML file
pub fn load_meta_config(content_type: &str, language: &str) -> Result<MetaConfig, String> {
    let cache_key = format!("{content_type}:{language}");

    // Check cache first
    if let Ok(cache) = META_CACHE.read() {
        if let Some(config) = cache.get(&cache_key) {
            return Ok(config.clone());
        }
    }

    // Load from file will be done in platform-specific section

    #[cfg(not(target_arch = "wasm32"))]
    {
        use std::fs;

        // Use environment variables for configurable content locations
        let server_content_root = {
            let public_path =
                std::env::var("SITE_PUBLIC_PATH").unwrap_or_else(|_| "public".to_string());
            let server_root_content =
                std::env::var("SITE_SERVER_ROOT_CONTENT").unwrap_or_else(|_| "r".to_string());
            format!("{}/{}", public_path, server_root_content)
        };

        // Try to read from filter-index.json (new index-based system)
        let filter_index_path = format!(
            "{}/{}/{}/filter-index.json",
            server_content_root, content_type, language
        );
        let config: MetaConfig = if std::path::Path::new(&filter_index_path).exists() {
            let json_content = fs::read_to_string(&filter_index_path).map_err(|e| {
                format!("Failed to read filter-index JSON file {filter_index_path}: {e}")
            })?;

            // Parse filter-index.json and extract categories/tags emojis
            let filter_index: serde_json::Value = serde_json::from_str(&json_content)
                .map_err(|e| format!("Failed to parse filter-index JSON: {e}"))?;

            let mut categories_emojis = HashMap::new();
            let mut tags_emojis = HashMap::new();

            // Extract categories emojis (handle both object and array formats)
            if let Some(categories) = filter_index.get("categories") {
                if let Some(categories_obj) = categories.as_object() {
                    // New format: {"rust": {"emoji": "🦀"}}
                    for (key, value) in categories_obj {
                        if let Some(emoji) = value.get("emoji").and_then(|e| e.as_str()) {
                            categories_emojis.insert(key.clone(), emoji.to_string());
                        } else {
                            // Fallback: no emoji data, use empty string
                            categories_emojis.insert(key.clone(), "".to_string());
                        }
                    }
                } else if let Some(categories_array) = categories.as_array() {
                    // Legacy format: ["rust", "devops"]
                    for category in categories_array {
                        if let Some(category_str) = category.as_str() {
                            categories_emojis.insert(category_str.to_string(), "".to_string());
                        }
                    }
                }
            }

            // Extract tags emojis (handle both object and array formats)
            if let Some(tags) = filter_index.get("tags") {
                if let Some(tags_obj) = tags.as_object() {
                    // New format: {"leptos": {"emoji": "🌟"}}
                    for (key, value) in tags_obj {
                        if let Some(emoji) = value.get("emoji").and_then(|e| e.as_str()) {
                            tags_emojis.insert(key.clone(), emoji.to_string());
                        } else {
                            // Fallback: no emoji data, use empty string
                            tags_emojis.insert(key.clone(), "".to_string());
                        }
                    }
                } else if let Some(tags_array) = tags.as_array() {
                    // Legacy format: ["rust", "web-development"]
                    for tag in tags_array {
                        if let Some(tag_str) = tag.as_str() {
                            tags_emojis.insert(tag_str.to_string(), "".to_string());
                        }
                    }
                }
            }

            MetaConfig {
                categories_emojis,
                tags_emojis,
            }
        } else {
            // No filter-index.json found, return empty meta config
            tracing::warn!(
                "No filter-index.json found at {}, using empty meta config",
                filter_index_path
            );
            MetaConfig {
                categories_emojis: HashMap::new(),
                tags_emojis: HashMap::new(),
            }
        };

        // Cache the result
        if let Ok(mut cache) = META_CACHE.write() {
            cache.insert(cache_key, config.clone());
        }

        Ok(config)
    }

    #[cfg(target_arch = "wasm32")]
    {
        // On WASM, lazy load from API and cache the result
        // First check if we already have a cached result
        if let Ok(cache) = META_CACHE.read() {
            if let Some(config) = cache.get(&cache_key) {
                return Ok(config.clone());
            }
        }

        // If not cached, initiate async loading but return error for now
        // The async loading will populate the cache for future calls
        crate::categories::wasm::initiate_meta_config_loading(
            content_type,
            language,
            cache_key.clone(),
        );

        // For now, return a basic error - components should handle gracefully
        // Future calls will get the cached result once async loading completes
        Err(format!(
            "Meta config loading initiated for {}/{}",
            content_type, language
        ))
    }
}

/// Clear meta cache (useful for development/testing)
#[allow(dead_code)]
pub fn clear_categories_cache() {
    if let Ok(mut cache) = META_CACHE.write() {
        cache.clear();
    }
}

/// Force clear cache on module load for development
#[cfg(debug_assertions)]
fn _clear_cache_on_load() {
    clear_categories_cache();
}

#[cfg(debug_assertions)]
static _INIT: std::sync::Once = std::sync::Once::new();

/// Auto-clear cache in debug mode
#[cfg(debug_assertions)]
pub fn ensure_fresh_cache() {
    _INIT.call_once(|| {
        _clear_cache_on_load();
    });
}
