//! Language-agnostic resource loader with registration system support
//!
//! Resources are loaded from:
//! 1. Registration system (populated by build.rs or plugins)
//! 2. Configuration files (SITE_CONFIG_PATH)
//! 3. Filesystem fallback (runtime loading from SITE_UI_PATH)
//!
//! This replaces the conditional compilation approach with a cleaner,
//! plugin-friendly registration pattern.

// Get menu resource from registration system or fallback
fn get_menu_resource(key: &str) -> Option<&'static str> {
    // First, try the registration system (populated by build.rs or WASM init)
    // Box::leak is intentional: converts owned String to &'static str for cached
    // resources
    if let Some(content) = super::super::registration::get_menu(key) {
        return Some(Box::leak(content.into_boxed_str()));
    }

    // PAP-compliant runtime loading from configured menu paths
    load_menu_from_filesystem(key)
}

/// Load menu resource from filesystem at runtime (PAP-compliant fallback)
/// Uses SITE_UI_PATH and manifest system for path resolution
#[cfg(not(has_generated_resources))]
fn load_menu_from_filesystem(key: &str) -> Option<&'static str> {
    use std::path::Path;

    // Parse the key format: "en" (language code)
    let language = key;

    // Try multiple path resolutions (respecting PAP - configuration-driven)
    let ui_paths = vec![
        // Environment variable first (most explicit)
        std::env::var("SITE_UI_PATH").ok(),
        // Try manifest system for project root
        if let Ok(manifest) = rustelo_utils::ManifestResolver::load() {
            Some(format!("{}/site/ui", manifest.root().display()))
        } else {
            None
        },
        // Fallback relative paths
        Some("site/ui".to_string()),
        Some("./site/ui".to_string()),
    ];

    // Try to find and load the menu file
    for ui_path in ui_paths.into_iter().flatten() {
        let menu_file = Path::new(&ui_path)
            .join("menus")
            .join(format!("{}.toml", language));

        if menu_file.exists() {
            // Box::leak converts owned String to &'static str (safe for cached resources)
            if let Ok(content) = std::fs::read_to_string(&menu_file) {
                return Some(Box::leak(content.into_boxed_str()));
            }
        }
    }

    None
}

fn get_footer_resource(key: &str) -> Option<&'static str> {
    // Check runtime registry first (populated by WASM init or plugins)
    if let Some(content) = super::super::registration::get_footer(key) {
        return Some(Box::leak(content.into_boxed_str()));
    }

    #[cfg(has_generated_resources)]
    {
        generated::FOOTER_RESOURCES.get(key).copied()
    }
    #[cfg(not(has_generated_resources))]
    {
        let _ = key;
        None
    }
}

fn get_theme_resource(key: &str) -> Option<&'static str> {
    #[cfg(has_generated_resources)]
    {
        generated::THEME_RESOURCES.get(key).copied()
    }
    #[cfg(not(has_generated_resources))]
    {
        let _ = key; // Suppress unused warning
        None
    }
}

fn get_ftl_resource(key: &str) -> Option<&'static str> {
    #[cfg(has_generated_resources)]
    {
        generated::FTL_RESOURCES.get(key).copied()
    }
    #[cfg(not(has_generated_resources))]
    {
        let _ = key; // Suppress unused warning
        None
    }
}

fn get_content_resource(key: &str) -> Option<&'static str> {
    #[cfg(has_generated_resources)]
    {
        generated::CONTENT_RESOURCES.get(key).copied()
    }
    #[cfg(not(has_generated_resources))]
    {
        let _ = key; // Suppress unused warning
        None
    }
}

// Available functions that choose the appropriate source
fn get_available_menus() -> Vec<&'static str> {
    #[cfg(has_generated_resources)]
    {
        generated::available_menus()
    }
    #[cfg(not(has_generated_resources))]
    {
        // Discover available menus from filesystem
        discover_available_menus_from_filesystem()
    }
}

/// Discover available menus from filesystem
#[cfg(not(has_generated_resources))]
fn discover_available_menus_from_filesystem() -> Vec<&'static str> {
    use std::path::Path;

    // Try to find menus directory
    let ui_paths = vec![
        std::env::var("SITE_UI_PATH").ok(),
        if let Ok(manifest) = rustelo_utils::ManifestResolver::load() {
            Some(format!("{}/site/ui", manifest.root().display()))
        } else {
            None
        },
        Some("site/ui".to_string()),
        Some("./site/ui".to_string()),
    ];

    let mut menus = Vec::new();

    for ui_path in ui_paths.into_iter().flatten() {
        let menus_dir = Path::new(&ui_path).join("menus");

        if menus_dir.exists() {
            if let Ok(entries) = std::fs::read_dir(&menus_dir) {
                for entry in entries.flatten() {
                    let path = entry.path();
                    if let Some(extension) = path.extension() {
                        if extension == "toml" {
                            if let Some(stem) = path.file_stem().and_then(|s| s.to_str()) {
                                // Box::leak returns &'static mut str, cast to &'static str
                                let leaked: &'static mut str =
                                    Box::leak(stem.to_string().into_boxed_str());
                                menus.push(&*leaked);
                            }
                        }
                    }
                }
            }
            // Found menus directory, no need to try other paths
            break;
        }
    }

    menus
}

fn get_available_footers() -> Vec<&'static str> {
    #[cfg(has_generated_resources)]
    {
        generated::available_footers()
    }
    #[cfg(not(has_generated_resources))]
    {
        vec![]
    }
}

fn get_available_themes() -> Vec<&'static str> {
    #[cfg(has_generated_resources)]
    {
        generated::available_themes()
    }
    #[cfg(not(has_generated_resources))]
    {
        vec![]
    }
}

fn get_available_ftl_resources() -> Vec<&'static str> {
    #[cfg(has_generated_resources)]
    {
        generated::available_ftl_resources()
    }
    #[cfg(not(has_generated_resources))]
    {
        vec![]
    }
}

fn get_available_content_resources() -> Vec<&'static str> {
    #[cfg(has_generated_resources)]
    {
        generated::available_content_resources()
    }
    #[cfg(not(has_generated_resources))]
    {
        vec![]
    }
}

/// Resource loading error
#[derive(Debug, thiserror::Error)]
pub enum ResourceError {
    #[error("Resource '{name}' not found")]
    NotFound { name: String },
    #[error("TOML parsing error: {0}")]
    TomlError(#[from] toml::de::Error),
}

/// Resource loader trait for type-safe loading
pub trait ResourceLoader<T> {
    fn load(&self, name: &str) -> Result<T, ResourceError>;
    fn available() -> Vec<&'static str>;
}

/// Menu resource loader
pub struct MenuLoader;

impl ResourceLoader<crate::MenuConfig> for MenuLoader {
    fn load(&self, language: &str) -> Result<crate::MenuConfig, ResourceError> {
        let content = get_menu_resource(language).ok_or_else(|| ResourceError::NotFound {
            name: format!("menu/{language}"),
        })?;

        let simple_config: crate::SimpleMenuConfig = toml::from_str(content)?;
        Ok(crate::MenuConfig {
            menu: simple_config
                .menu
                .into_iter()
                .map(|item| crate::MenuItem {
                    route: item.route,
                    label: item.label,
                    icon: item.icon,
                    priority: item.priority,
                    is_external: item.is_external,
                    localized_routes: item.localized_routes,
                    auth_required: item.auth_required,
                })
                .collect(),
            footer: crate::FooterConfig {
                title: String::new(),
                company_desc: String::new(),
                copyright_text: String::new(),
                social_links: vec![],
                sections: vec![],
                menu: vec![],
            },
        })
    }

    fn available() -> Vec<&'static str> {
        get_available_menus()
    }
}

/// Footer resource loader that uses menu items as single source of truth
pub struct FooterLoader;

impl ResourceLoader<crate::FooterConfig> for FooterLoader {
    fn load(&self, language: &str) -> Result<crate::FooterConfig, ResourceError> {
        // Try to load footer-specific config for copyright, social links, etc.
        let footer_specific = if let Some(content) = get_footer_resource(language) {
            toml::from_str::<crate::FooterConfig>(content).ok()
        } else {
            None
        };

        // Only use footer-specific menu items from footer TOML - no main navigation
        // filtering
        let mut footer_menu_items: Vec<crate::MenuItem> = Vec::new();

        // Add footer-specific menu items from footer TOML
        if let Some(ref footer) = footer_specific {
            // Add menu items from the footer TOML's [[menu]] section
            for menu_item in &footer.menu {
                footer_menu_items.push(crate::MenuItem {
                    route: menu_item.route.clone(),
                    label: menu_item.label.clone(),
                    icon: menu_item.icon.clone(),
                    priority: menu_item.priority,
                    is_external: menu_item.is_external,
                    localized_routes: menu_item.localized_routes.clone(),
                    auth_required: menu_item.auth_required,
                });
            }

            // Also add menu items from sections if they exist
            for section in &footer.sections {
                for footer_link in &section.links {
                    footer_menu_items.push(crate::MenuItem {
                        route: footer_link.route.clone(),
                        label: footer_link.label.clone(),
                        icon: None,
                        priority: None,
                        is_external: footer_link.is_external,
                        localized_routes: None,
                        auth_required: false,
                    });
                }
            }
        }

        // Return footer config directly from TOML, with menu items added to sections
        if let Some(mut footer) = footer_specific {
            // If we have footer menu items, add them as a section
            if !footer_menu_items.is_empty() {
                // Create dynamic translations for "Links" using i18n system
                let available_languages = crate::i18n::discovery::discover_available_languages();
                let mut link_translations = Vec::new();

                for lang in available_languages {
                    // Use the i18n system to get the proper translation for "footer-links"
                    let translation = crate::i18n::t_for_language(lang, "footer-links");
                    link_translations.push((lang.clone(), translation));
                }

                footer.sections.push(crate::FooterSection {
                    title: crate::Translations::from_pairs(link_translations),
                    links: footer_menu_items
                        .into_iter()
                        .map(|item| crate::FooterLink {
                            route: item.route,
                            label: item.label,
                            is_external: item.is_external,
                        })
                        .collect(),
                });
            }
            Ok(footer)
        } else {
            // Fallback when no footer TOML exists
            Ok(crate::FooterConfig::new())
        }
    }

    fn available() -> Vec<&'static str> {
        get_available_footers()
    }
}

/// Theme resource loader
pub struct ThemeLoader;

impl ResourceLoader<crate::ThemeConfig> for ThemeLoader {
    fn load(&self, name: &str) -> Result<crate::ThemeConfig, ResourceError> {
        let content = get_theme_resource(name).ok_or_else(|| ResourceError::NotFound {
            name: format!("theme/{name}"),
        })?;

        toml::from_str(content).map_err(ResourceError::from)
    }

    fn available() -> Vec<&'static str> {
        get_available_themes()
    }
}

/// FTL resource loader for fluent localization files
pub struct FtlLoader;

impl ResourceLoader<String> for FtlLoader {
    fn load(&self, name: &str) -> Result<String, ResourceError> {
        let content = get_ftl_resource(name).ok_or_else(|| ResourceError::NotFound {
            name: format!("ftl/{name}"),
        })?;

        Ok(content.to_string())
    }

    fn available() -> Vec<&'static str> {
        get_available_ftl_resources()
    }
}

// ✅ NO hardcoded paths!
// All resources are auto-discovered by build script and included above

/// Convenient loading functions
pub mod load {
    use super::*;

    /// Load menu with dynamic language fallback
    pub fn menu(language: &str) -> Result<crate::MenuConfig, ResourceError> {
        let default_lang = crate::i18n::discovery::get_default_language();
        MenuLoader
            .load(language)
            .or_else(|_| MenuLoader.load(default_lang))
    }

    /// Load footer with dynamic language fallback
    pub fn footer(language: &str) -> Result<crate::FooterConfig, ResourceError> {
        let default_lang = crate::i18n::discovery::get_default_language();
        FooterLoader
            .load(language)
            .or_else(|_| FooterLoader.load(default_lang))
    }

    /// Load theme with default fallback
    pub fn theme(name: &str) -> Result<crate::ThemeConfig, ResourceError> {
        ThemeLoader
            .load(name)
            .or_else(|_| ThemeLoader.load("default"))
    }

    /// Load FTL file content
    pub fn ftl(name: &str) -> Result<String, ResourceError> {
        FtlLoader.load(name)
    }

    /// Load FTL file for specific language and file with dynamic fallback
    pub fn ftl_for_lang(language: &str, file: &str) -> Result<String, ResourceError> {
        let key = format!("{language}_{file}");
        FtlLoader.load(&key).or_else(|_| {
            // Fallback to default language if the requested language is not available
            let default_lang = crate::i18n::discovery::get_default_language();
            let fallback_key = format!("{default_lang}_{file}");
            FtlLoader.load(&fallback_key)
        })
    }

    /// Get available resources (auto-discovered or fallback)
    pub fn available_menus() -> Vec<&'static str> {
        super::get_available_menus()
    }

    pub fn available_footers() -> Vec<&'static str> {
        super::get_available_footers()
    }

    pub fn available_themes() -> Vec<&'static str> {
        super::get_available_themes()
    }

    pub fn available_ftl_resources() -> Vec<&'static str> {
        super::get_available_ftl_resources()
    }

    pub fn available_content_resources() -> Vec<&'static str> {
        super::get_available_content_resources()
    }

    /// Load content JSON file
    pub fn content(name: &str) -> Result<String, ResourceError> {
        let content = super::get_content_resource(name).ok_or_else(|| ResourceError::NotFound {
            name: format!("content/{name}"),
        })?;
        Ok(content.to_string())
    }
}

/// Macro for easy resource definition
#[macro_export]
macro_rules! define_resource {
    ($name:ident, $type:ty, $resources:expr) => {
        pub struct $name;

        impl ResourceLoader<$type> for $name {
            fn load(&self, name: &str) -> Result<$type, ResourceError> {
                let resources: &[(&str, &str)] = &$resources;
                let content = resources
                    .iter()
                    .find(|(key, _)| *key == name)
                    .map(|(_, content)| *content)
                    .ok_or_else(|| ResourceError::NotFound {
                        name: name.to_string(),
                    })?;

                toml::from_str(content).map_err(ResourceError::from)
            }

            fn available() -> Vec<&'static str> {
                let resources: &[(&str, &str)] = &$resources;
                resources.iter().map(|(key, _)| *key).collect()
            }
        }
    };
}

// Usage example:
// define_resource!(CustomLoader, CustomConfig, [
//     ("config1", include_str!("path/to/config1.toml")),
//     ("config2", include_str!("path/to/config2.toml")),
// ]);
