//! # RUSTELO Shared
//!
//! <div align="center">
//!   <img src="../logos/rustelo_dev-logo-h.svg" alt="RUSTELO" width="300" />
//! </div>
//!
//! Shared types, utilities, and functionality for the RUSTELO web application framework.
//!
//! ## Overview
//!
//! The shared crate contains common types, utilities, and functionality that are used across
//! both the client and server components of RUSTELO applications. This includes authentication
//! types, content management structures, internationalization support, and configuration utilities.
//!
//! ## Features
//!
//! - **🔐 Authentication Types** - Shared auth structures and utilities
//! - **📄 Content Management** - Common content types and processing
//! - **🌐 Internationalization** - Multi-language support with Fluent
//! - **⚙️ Configuration** - Shared configuration management
//! - **🎨 Menu System** - Navigation and menu configuration
//! - **📋 Type Safety** - Strongly typed interfaces for client-server communication
//!
//! ## Architecture
//!
//! The shared crate is organized into several key modules:
//!
//! - [`auth`] - Authentication types and utilities
//! - [`content`] - Content management types and processing
//!
//! Additional functionality includes:
//! - Menu configuration and internationalization
//! - Fluent resource management
//! - Content file loading utilities
//! - Type-safe configuration structures
//!
//! ## Quick Start
//!
//! ### Menu Configuration
//!
//! ```rust
//! use shared::{MenuConfig, load_menu_toml};
//!
//! // Load menu from TOML file
//! let menu = load_menu_toml().unwrap_or_default();
//!
//! // Access menu items
//! for item in menu.menu {
//!     println!("Route: {}, Label (EN): {}", item.route, item.label.en);
//! }
//! ```
//!
//! ### Internationalization
//!
//! ```rust
//! use shared::{get_bundle, t};
//! use std::collections::HashMap;
//!
//! // Get localization bundle
//! let bundle = get_bundle("en").expect("Failed to load English bundle");
//!
//! // Translate text
//! let welcome_msg = t(&bundle, "welcome", None);
//! println!("{}", welcome_msg);
//!
//! // Translate with arguments
//! let mut args = HashMap::new();
//! args.insert("name", "RUSTELO");
//! let greeting = t(&bundle, "greeting", Some(&args));
//! ```
//!
//! ## Type Definitions
//!
//! ### Menu System
//!
//! ```rust
//! use shared::{MenuConfig, MenuItem, MenuLabel};
//!
//! let menu_item = MenuItem {
//!     route: "/about".to_string(),
//!     label: MenuLabel {
//!         en: "About".to_string(),
//!         es: "Acerca de".to_string(),
//!     },
//! };
//! ```
//!
//! ### Text Localization
//!
//! ```rust
//! use shared::Texts;
//! use std::collections::HashMap;
//!
//! let mut texts = Texts::default();
//! texts.en.insert("welcome".to_string(), "Welcome".to_string());
//! texts.es.insert("welcome".to_string(), "Bienvenido".to_string());
//! ```
//!
//! ## Internationalization Support
//!
//! RUSTELO uses [Fluent](https://projectfluent.org/) for internationalization:
//!
//! - **Resource Loading** - Automatic loading of .ftl files
//! - **Language Fallback** - Graceful fallback to English
//! - **Parameter Substitution** - Dynamic text with variables
//! - **Pluralization** - Proper plural forms for different languages
//!
//! ### Supported Languages
//!
//! - **English (en)** - Primary language
//! - **Spanish (es)** - Secondary language
//! - **Extensible** - Easy to add more languages
//!
//! ## Configuration Management
//!
//! The shared crate provides utilities for loading configuration from various sources:
//!
//! - **TOML Files** - Structured configuration files
//! - **Environment Variables** - Runtime configuration
//! - **Fallback Defaults** - Graceful degradation
//!
//! ## Error Handling
//!
//! All functions return `Result` types for proper error handling:
//!
//! ```rust
//! use shared::load_menu_toml;
//!
//! match load_menu_toml() {
//!     Ok(menu) => println!("Loaded {} menu items", menu.menu.len()),
//!     Err(e) => eprintln!("Failed to load menu: {}", e),
//! }
//! ```
//!
//! ## Cross-Platform Support
//!
//! The shared crate is designed to work across different targets:
//!
//! - **Server** - Native Rust environments
//! - **Client** - WebAssembly (WASM) environments
//! - **Testing** - Development and CI environments
//!
//! ## Performance Considerations
//!
//! - **Lazy Loading** - Resources loaded on demand
//! - **Caching** - Efficient resource reuse
//! - **Memory Management** - Careful memory usage for WASM
//! - **Bundle Size** - Optimized for small WASM bundles
//!
//! ## Examples
//!
//! ### Creating a Multi-language Menu
//!
//! ```rust
//! use shared::{MenuConfig, MenuItem, MenuLabel};
//!
//! let menu = MenuConfig {
//!     menu: vec![
//!         MenuItem {
//!             route: "/".to_string(),
//!             label: MenuLabel {
//!                 en: "Home".to_string(),
//!                 es: "Inicio".to_string(),
//!             },
//!         },
//!         MenuItem {
//!             route: "/about".to_string(),
//!             label: MenuLabel {
//!                 en: "About".to_string(),
//!                 es: "Acerca de".to_string(),
//!             },
//!         },
//!     ],
//! };
//! ```
//!
//! ### Loading and Using Fluent Resources
//!
//! ```rust
//! use shared::{get_bundle, t};
//! use std::collections::HashMap;
//!
//! // Load Spanish bundle
//! let bundle = get_bundle("es").expect("Failed to load Spanish bundle");
//!
//! // Simple translation
//! let app_title = t(&bundle, "app-title", None);
//!
//! // Translation with variables
//! let mut args = HashMap::new();
//! args.insert("user", "María");
//! let welcome = t(&bundle, "welcome-user", Some(&args));
//! ```
//!
//! ## Contributing
//!
//! When adding new shared functionality:
//!
//! 1. **Keep it Generic** - Ensure it's useful for both client and server
//! 2. **Document Types** - Add comprehensive documentation
//! 3. **Handle Errors** - Use proper error types and handling
//! 4. **Test Thoroughly** - Add tests for all platforms
//! 5. **Consider Performance** - Optimize for WASM environments
//!
//! ## License
//!
//! This project is licensed under the MIT License - see the [LICENSE](https://github.com/yourusername/rustelo/blob/main/LICENSE) file for details.

#![allow(unused_imports)]
#![allow(dead_code)]

pub mod auth;
pub mod content;

use fluent::{FluentBundle, FluentResource};
use fluent_bundle::FluentArgs;

use serde::Deserialize;
use std::borrow::Cow;
use std::collections::HashMap;
use unic_langid::LanguageIdentifier;

#[derive(Debug, Clone, Deserialize, PartialEq)]
pub struct MenuLabel {
    pub en: String,
    pub es: String,
}

impl Default for MenuLabel {
    fn default() -> Self {
        Self {
            en: "Menu".to_string(),
            es: "Menú".to_string(),
        }
    }
}

#[derive(Debug, Clone, Deserialize, PartialEq)]
pub struct MenuItem {
    pub route: String,
    pub is_external: bool,
    pub label: MenuLabel,
}

impl Default for MenuItem {
    fn default() -> Self {
        Self {
            route: "/".to_string(),
            is_external: false,
            label: MenuLabel::default(),
        }
    }
}

#[derive(Debug, Clone, Deserialize, PartialEq)]
pub struct MenuConfig {
    pub menu: Vec<MenuItem>,
}

impl Default for MenuConfig {
    fn default() -> Self {
        Self {
            menu: vec![
                MenuItem {
                    route: "/".to_string(),
                    is_external: false,
                    label: MenuLabel {
                        en: "Home".to_string(),
                        es: "Inicio".to_string(),
                    },
                },
                MenuItem {
                    route: "/about".to_string(),
                    is_external: false,
                    label: MenuLabel {
                        en: "About".to_string(),
                        es: "Acerca de".to_string(),
                    },
                },
            ],
        }
    }
}

#[derive(Debug, Clone, Deserialize, PartialEq)]
pub struct Texts {
    pub en: std::collections::HashMap<String, String>,
    pub es: std::collections::HashMap<String, String>,
}

impl Default for Texts {
    fn default() -> Self {
        Self {
            en: std::collections::HashMap::new(),
            es: std::collections::HashMap::new(),
        }
    }
}

// Load FTL resources from files instead of hardcoded content
fn load_en_ftl() -> &'static str {
    Box::leak(
        std::fs::read_to_string(
            get_content_path("en.ftl")
                .unwrap_or_else(|_| std::path::PathBuf::from("content/en.ftl")),
        )
        .unwrap_or_else(|_| "app-title = Rustelo App\nwelcome = Welcome".to_string())
        .into_boxed_str(),
    )
}

fn load_es_ftl() -> &'static str {
    Box::leak(
        std::fs::read_to_string(
            get_content_path("es.ftl")
                .unwrap_or_else(|_| std::path::PathBuf::from("content/es.ftl")),
        )
        .unwrap_or_else(|_| "app-title = Aplicación Rustelo\nwelcome = Bienvenido".to_string())
        .into_boxed_str(),
    )
}

// Dynamic FTL resources loaded from files
static EN_FTL: std::sync::OnceLock<&str> = std::sync::OnceLock::new();
static ES_FTL: std::sync::OnceLock<&str> = std::sync::OnceLock::new();

fn get_en_ftl() -> &'static str {
    EN_FTL.get_or_init(|| load_en_ftl())
}

fn get_es_ftl() -> &'static str {
    ES_FTL.get_or_init(|| load_es_ftl())
}

// Content loading utilities
use std::path::PathBuf;

pub fn get_content_path(filename: &str) -> Result<PathBuf, Box<dyn std::error::Error>> {
    // Try to get root path from environment or use current directory
    let root_path = std::env::var("ROOT_PATH")
        .map(PathBuf::from)
        .unwrap_or_else(|_| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")));

    let content_path = root_path.join("content").join(filename);

    // If the file exists, return the path
    if content_path.exists() {
        Ok(content_path)
    } else {
        // Fallback to relative path
        let fallback_path = PathBuf::from("content").join(filename);
        if fallback_path.exists() {
            Ok(fallback_path)
        } else {
            Err(format!("Content file not found: {}", filename).into())
        }
    }
}

pub fn get_bundle(lang: &str) -> Result<FluentBundle<FluentResource>, Box<dyn std::error::Error>> {
    let langid: LanguageIdentifier = lang.parse().unwrap_or_else(|_| {
        "en".parse().unwrap_or_else(|e| {
            eprintln!(
                "Critical error: Default language 'en' failed to parse: {}",
                e
            );
            // This should never happen, but we'll create a minimal fallback
            LanguageIdentifier::from_parts(
                unic_langid::subtags::Language::from_bytes(b"en").unwrap_or_else(|e| {
                    eprintln!("Critical error: failed to create 'en' language: {}", e);
                    // Fallback to creating a new language identifier from scratch
                    match "en".parse::<unic_langid::subtags::Language>() {
                        Ok(lang) => lang,
                        Err(_) => {
                            // If even this fails, we'll use the default language
                            eprintln!("Using default language as final fallback");
                            unic_langid::subtags::Language::default()
                        }
                    }
                }),
                None,
                None,
                &[],
            )
        })
    });
    let ftl_str = match lang {
        "es" => get_es_ftl(),
        _ => get_en_ftl(),
    };
    let res = FluentResource::try_new(ftl_str.to_string())
        .map_err(|e| format!("Failed to parse FTL resource: {:?}", e))?;
    let mut bundle = FluentBundle::new(vec![langid]);
    bundle
        .add_resource(res)
        .map_err(|e| format!("Failed to add FTL resource to bundle: {:?}", e))?;
    Ok(bundle)
}

pub fn t(
    bundle: &FluentBundle<FluentResource>,
    key: &str,
    args: Option<&HashMap<&str, &str>>,
) -> String {
    let msg = bundle.get_message(key).and_then(|m| m.value());
    if let Some(msg) = msg {
        let mut errors = vec![];
        let fargs = args.map(|a| {
            let mut f = FluentArgs::new();
            for (k, v) in a.iter() {
                f.set(*k, *v);
            }
            f
        });
        bundle
            .format_pattern(msg, fargs.as_ref(), &mut errors)
            .to_string()
    } else {
        key.to_string()
    }
}

pub fn load_menu_toml() -> Result<MenuConfig, Box<dyn std::error::Error>> {
    // Use embedded menu data for consistent server-client rendering
    const MENU_TOML: &str = include_str!("../../content/menu.toml");
    toml::from_str(MENU_TOML)
        .map_err(|e| format!("Failed to parse embedded menu.toml: {}", e).into())
}

pub fn load_texts_toml() -> Result<Texts, Box<dyn std::error::Error>> {
    // Try to load from file system first
    match get_content_path("texts.toml") {
        Ok(path) => {
            let content = std::fs::read_to_string(&path)
                .map_err(|e| format!("Failed to read texts.toml from {}: {}", path.display(), e))?;
            toml::from_str(&content)
                .map_err(|e| format!("Failed to parse texts.toml: {}", e).into())
        }
        Err(_) => {
            // Return default texts if file not found
            Ok(Texts {
                en: std::collections::HashMap::new(),
                es: std::collections::HashMap::new(),
            })
        }
    }
}
