//! Locale file loader for Fluent and TOML translations

use crate::error::{ErrorWrapper, Result};
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use unic_langid::LanguageIdentifier;

/// Loader for locale files (both .ftl and .toml)
pub struct LocaleLoader {
    locales_path: PathBuf,
}

impl LocaleLoader {
    /// Create a new locale loader with the given locales directory path
    pub fn new(locales_path: PathBuf) -> Self {
        Self { locales_path }
    }

    /// Load Fluent (.ftl) resources for a specific locale
    ///
    /// Searches for files matching `locales/{locale}/*.ftl`
    pub fn load_fluent(&self, locale: &LanguageIdentifier) -> Result<Vec<String>> {
        let locale_dir = self.locales_path.join(locale.to_string());

        if !locale_dir.exists() {
            return Err(ErrorWrapper::i18n_failed(format!(
                "Locale directory not found: {:?}",
                locale_dir
            )));
        }

        let mut resources = Vec::new();

        match fs::read_dir(&locale_dir) {
            Ok(entries) => {
                for entry in entries.flatten() {
                    let path = entry.path();

                    if path.extension().and_then(|s| s.to_str()) == Some("ftl") {
                        match fs::read_to_string(&path) {
                            Ok(content) => resources.push(content),
                            Err(e) => {
                                return Err(ErrorWrapper::i18n_failed(format!(
                                    "Failed to read {:?}: {}",
                                    path, e
                                )))
                            }
                        }
                    }
                }
            }
            Err(e) => {
                return Err(ErrorWrapper::i18n_failed(format!(
                    "Failed to read locale directory {:?}: {}",
                    locale_dir, e
                )))
            }
        }

        Ok(resources)
    }

    /// Load TOML-based translations for a specific locale
    ///
    /// Searches for file `locales/{locale}.toml` and flattens nested structure
    pub fn load_toml(&self, locale: &LanguageIdentifier) -> Result<HashMap<String, String>> {
        let toml_file = self.locales_path.join(format!("{}.toml", locale));

        if !toml_file.exists() {
            return Ok(HashMap::new());
        }

        match fs::read_to_string(&toml_file) {
            Ok(content) => match toml::from_str::<toml::map::Map<String, toml::Value>>(&content) {
                Ok(root) => Ok(Self::flatten_toml(root, "")),
                Err(e) => Err(ErrorWrapper::i18n_failed(format!(
                    "Failed to parse TOML file {:?}: {}",
                    toml_file, e
                ))),
            },
            Err(e) => Err(ErrorWrapper::i18n_failed(format!(
                "Failed to read TOML file {:?}: {}",
                toml_file, e
            ))),
        }
    }

    /// Flatten nested TOML structure into dot-notation keys
    ///
    /// Example: `[forms.registration] username = "Name"` → `"forms.registration.username": "Name"`
    fn flatten_toml(
        map: toml::map::Map<String, toml::Value>,
        prefix: &str,
    ) -> HashMap<String, String> {
        let mut result = HashMap::new();

        for (key, value) in map {
            let full_key = if prefix.is_empty() {
                key.clone()
            } else {
                format!("{}.{}", prefix, key)
            };

            match value {
                toml::Value::String(s) => {
                    result.insert(full_key, s);
                }
                toml::Value::Table(table) => {
                    let nested = Self::flatten_toml(table, &full_key);
                    result.extend(nested);
                }
                toml::Value::Array(arr) => {
                    // For arrays, convert to JSON representation
                    if let Ok(json) = serde_json::to_string(&arr) {
                        result.insert(full_key, json);
                    }
                }
                _ => {
                    // For other types, convert to string
                    result.insert(full_key, value.to_string());
                }
            }
        }

        result
    }
}

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

    #[test]
    fn test_flatten_toml() {
        let mut map = toml::map::Map::new();
        map.insert(
            "forms".to_string(),
            toml::Value::Table({
                let mut t = toml::map::Map::new();
                t.insert(
                    "registration".to_string(),
                    toml::Value::Table({
                        let mut t2 = toml::map::Map::new();
                        t2.insert(
                            "title".to_string(),
                            toml::Value::String("Registration".to_string()),
                        );
                        t2
                    }),
                );
                t
            }),
        );

        let flattened = LocaleLoader::flatten_toml(map, "");
        assert_eq!(
            flattened.get("forms.registration.title"),
            Some(&"Registration".to_string())
        );
    }
}
