include!(concat!(env!("OUT_DIR"), "/translations.rs"));

use leptos::prelude::*;
use rust_shared::i18n::{Language, LanguageContext as SharedLanguageContext, preload_translations_from_keys, init_translation_dictionary};
use rust_shared::HashMap;
use crate::auth::use_auth;
use color_eyre::Result;
use std::sync::Once;
use std::default::Default;

#[cfg(feature = "hydrate")]
use web_sys::js_sys::Date;

/// Leptos-specific wrapper around the generic LanguageContext
/// This provides reactive integration with Leptos signals
#[derive(Clone, Debug)]
pub struct LeptosLanguageContext {
    pub current_language: RwSignal<Language>,
    shared_context: SharedLanguageContext,
}

/// Reactive translation context with signals for each language
#[derive(Clone, Debug)]
pub struct LeptosTranslationContext {
    pub en_translations: RwSignal<HashMap<String, String>>,
    pub ru_translations: RwSignal<HashMap<String, String>>,
}

impl LeptosTranslationContext {
    pub fn new() -> Self {
        Self {
            en_translations: RwSignal::new(HashMap::default()),
            ru_translations: RwSignal::new(HashMap::default()),
        }
    }
    
    /// Update translations for both languages
    pub fn update_translations(&self, en: HashMap<String, String>, ru: HashMap<String, String>) {
        log::info!("Updating reactive translations: {} EN, {} RU", en.len(), ru.len());
        
        //for (key, value) in en.iter() {
        //    log::info!("update_translations: EN: '{}' -> '{}'", key, value);
        //}
        //for (key, value) in ru.iter() {
        //    log::info!("update_translations: RU: '{}' -> '{}'", key, value);
        //}
        
        
        self.en_translations.set(en);
        self.ru_translations.set(ru);
        log::info!("Reactive translations updated successfully");
    }
    
    /// Get translation for specific language with custom module path
    pub fn get_translation_with_module(&self, text: &str, language: Language, module_path: &str) -> Option<String> {
        let translations = if language == Language::Ru {
            self.ru_translations.get()
        } else {
            self.en_translations.get()
        };
        
        // Extract module name from the passed path
        let module_name = module_path.splitn(3, ':').nth(2).unwrap_or(module_path);
        let id = hash_string(text, module_name);
        
        //log::debug!("get_translation: looking for '{}' (id: {}) in language {:?}", text, id, language);
        //log::debug!("get_translation: dictionary has {} entries", translations.len());
        
        // Log first few keys for debugging
        let keys: Vec<String> = translations.keys().take(5).cloned().collect();
        //log::debug!("get_translation: sample keys: {:?}", keys);
        
        if let Some(translation) = translations.get(&id) {
            //log::debug!("get_translation: found '{}' -> '{}'", text, translation);
            Some(translation.clone())
        } else {
            //log::warn!("get_translation: not found '{}' (id: {}) in language {:?}", text, id, language);
            None
        }
    }
}

impl LeptosLanguageContext {
    pub fn new() -> Self {
        let current_language = RwSignal::new(Language::En);
        let shared_context = SharedLanguageContext::new();
        
        let signal_for_listener = current_language;
        shared_context.add_listener(move |lang| {
            signal_for_listener.set(lang);
        });
        
        Self {
            current_language,
            shared_context,
        }
    }
    
    /// Get the current language
    pub fn get_current_language(&self) -> Language {
        self.current_language.get()
    }
    
    /// Set the language and persist to localStorage
    pub fn set_language(&self, lang: Language) {
        self.current_language.set(lang);
        self.shared_context.set_language(lang);
        
        #[cfg(feature = "hydrate")]
        {
            if let Some(window) = web_sys::window() {
                if let Ok(Some(storage)) = window.local_storage() {
                    let lang_str = match lang {
                        Language::En => "en",
                        Language::Ru => "ru",
                    };
                    let _ = storage.set_item("user_language", lang_str);
                }
            }
        }
    }
    
    /// Update language from user profile (called when auth state changes)
    pub fn update_from_profile(&self) {
        let auth = use_auth();
        if let Some(profile) = auth.get_profile() {
            self.set_language(profile.language);
        }
    }
    
    /// Restore language from localStorage
    pub fn restore_from_storage(&self) {
        #[cfg(feature = "hydrate")]
        {
            if let Some(window) = web_sys::window() {
                if let Ok(Some(storage)) = window.local_storage() {
                    if let Ok(Some(lang_str)) = storage.get_item("user_language") {
                        let language = match lang_str.as_str() {
                            "ru" => Language::Ru,
                            "en" | _ => Language::En,
                        };
                        self.set_language(language);
                    } else {
                        // No stored language -> default to Russian
                        self.set_language(Language::Ru);
                    }
                }
            }
        }
    }
    
    /// Get the underlying shared context for thread-local usage
    pub fn shared_context(&self) -> &SharedLanguageContext {
        &self.shared_context
    }
}

/// Provide language context to the app
pub fn provide_language_context() -> LeptosLanguageContext {
    let lang_context = LeptosLanguageContext::new();
    
    provide_context(lang_context.clone());
    rust_shared::i18n::provide_language_context(lang_context.shared_context.clone());
    
    lang_context
}

/// Provide translation context to the app
pub fn provide_translation_context() -> LeptosTranslationContext {
    let translation_context = LeptosTranslationContext::new();
    provide_context(translation_context.clone());
    translation_context
}

/// Get the Leptos translation context
pub fn use_translation_context() -> LeptosTranslationContext {
    expect_context::<LeptosTranslationContext>()
}

/// Get the Leptos language context
pub fn use_language() -> LeptosLanguageContext {
    expect_context::<LeptosLanguageContext>()
}

/// Get the current user's language with fallback hierarchy
pub fn get_current_language() -> Language {
    if let Some(auth) = leptos::prelude::use_context::<crate::auth::AuthState>() {
        if let Some(profile) = auth.get_profile() {
            return profile.language;
        }
    }
    
    if let Some(lang_context) = leptos::prelude::use_context::<LeptosLanguageContext>() {
        return lang_context.get_current_language();
    }
    
    rust_shared::i18n::get_current_language()
}

/// Get language from current URL path
/// This works both on server and client side
pub fn get_language_from_url() -> Language {
    // Try to get language from router context first (works on both SSR and client)
    let location = leptos_router::hooks::use_location();
    let pathname = location.pathname.get();
    log::info!("get_language_from_url: pathname = '{}'", pathname);
    
    if pathname.starts_with("/ru") {
        log::info!("get_language_from_url: detected Russian language");
        return Language::Ru;
    }
    
    log::info!("get_language_from_url: using default Russian language");
    Language::En 
}

/// Get language from URL path (for use in components)
pub fn use_language_from_url() -> impl Fn() -> Language + Clone {
    let location = leptos_router::hooks::use_location();
    
    move || {
        let pathname = location.pathname.get();
        
        // Debug logging
        #[cfg(feature = "hydrate")]
        {
            if let Some(window) = web_sys::window() {
                let real_location = window.location();
                if let Ok(real_pathname) = real_location.pathname() {
                    if real_pathname.starts_with("/ru") {
                        return Language::Ru;
                    }
                }
            }
        }
        
        if pathname.starts_with("/ru") {
            Language::Ru
        } else {
            Language::En
        }
    }
}

pub use rust_shared::t8r as t8r_original;

/// Reactive translation macro that uses language from URL
/// This works with both SSR and client-side routing
#[macro_export]
macro_rules! t8s {
    ($text:literal) => {{
        // Try to get language from URL first
        let current_lang = $crate::i18n::get_language_from_url();
        log::info!("t8s! macro called with text: '{}', detected language: {:?}", $text, current_lang);
        rust_shared::t8x!($text, &current_lang)
    }};
    ($text:literal, $uniq:literal) => {{
        let current_lang = $crate::i18n::get_language_from_url();
        log::info!("t8s! macro called with text: '{}', uniq: '{}', detected language: {:?}", $text, $uniq, current_lang);
        rust_shared::t8x!($text, &current_lang, $uniq)
    }};
    ($text_language:expr, $text:literal) => {{
        let current_lang = $crate::i18n::get_language_from_url();
        log::info!("t8s! macro called with text: '{}', text_language: {:?}, detected language: {:?}", $text, $text_language, current_lang);
        rust_shared::t8x!($text_language, $text, &current_lang)
    }};
    ($text_language:expr, $text:literal, $uniq:literal) => {{
        let current_lang = $crate::i18n::get_language_from_url();
        log::info!("t8s! macro called with text: '{}', text_language: {:?}, uniq: '{}', detected language: {:?}", $text, $text_language, $uniq, current_lang);
        rust_shared::t8x!($text_language, $text, &current_lang, $uniq)
    }};
}

static INIT: Once = Once::new();

/// Initialize the i18n system with the VProxy Web API implementation
pub fn init_i18n() -> Result<()> {
    INIT.call_once(|| {
        log::info!("Initializing i18n system...");
        match init_translation_dictionary() {
            Ok(_) => log::info!("i18n system initialized successfully"),
            Err(e) => log::error!("Failed to initialize i18n system: {}", e),
        }
    });
    Ok(())
}

/// Preload all translations found in the codebase at compile time
pub async fn preload_all_translations() -> Result<()> {
    init_i18n()?;
    preload_translations_from_keys(get_all_translation_keys).await
}

/// Load translations from server (without sending keys)
pub async fn load_translations_from_server() -> Result<()> {
    log::info!("Starting translation loading from server...");
    
    init_i18n()?;
    log::debug!("i18n system initialized");
    
    // Get backend URL for client-side
    let backend_url = get_backend_url_for_client()?;
    log::info!("Using backend URL: {}", backend_url);
    
    // Load translations directly without using rust-shared functions
    log::info!("Loading translations from server...");
    let (en_translations, ru_translations) = load_translations_directly(&backend_url).await?;
    
    // Update reactive context if available
    if let Some(translation_context) = leptos::prelude::use_context::<LeptosTranslationContext>() {
        translation_context.update_translations(en_translations, ru_translations);
    }
    
    log::info!("Translations loaded from server successfully");
    Ok(())
}

/// Get backend URL for client-side (from meta tag or default)
fn get_backend_url_for_client() -> Result<String> {
    #[cfg(feature = "hydrate")]
    {
        // Try to get from meta tag first
        if let Some(window) = web_sys::window() {
            if let Some(document) = window.document() {
                if let Ok(Some(meta)) = document.query_selector("meta[name=\"backend-url\"]") {
                    if let Some(content) = meta.get_attribute("content") {
                        if !content.is_empty() {
                            log::info!("Using backend URL from meta tag: {}", content);
                            return Ok(content);
                        }
                    }
                }
            }
        }
        
        // Fallback to default localhost URL
        let default_url = "http://localhost:8080";
        log::info!("Using default backend URL: {}", default_url);
        return Ok(default_url.to_string());
    }
    
    // For SSR, BACKEND_URL should be available from environment
    #[cfg(not(feature = "hydrate"))]
    {
        Ok(std::env::var("BACKEND_URL")
            .unwrap_or_else(|_| "http://localhost:8080".to_string()))
    }
}

/// Load translations directly from API without using rust-shared functions
async fn load_translations_directly(backend_url: &str) -> Result<(HashMap<String, String>, HashMap<String, String>)> {
    use rust_shared::i18n::{Language, TRANSLATION_DICTIONARY};
    
    log::info!("Loading translations from backend: {}", backend_url);
    
    // Load English translations
    let en_url = format!("{}/rpc/i18n.dictionary?lang_code=eng", backend_url);
    log::info!("Fetching English translations from: {}", en_url);
    let en_translations = fetch_translations(&en_url).await?;
    log::info!("Loaded {} English translations", en_translations.len());
    
    // Load Russian translations
    let ru_url = format!("{}/rpc/i18n.dictionary?lang_code=rus", backend_url);
    log::info!("Fetching Russian translations from: {}", ru_url);
    let ru_translations = fetch_translations(&ru_url).await?;
    log::info!("Loaded {} Russian translations", ru_translations.len());
    
    // Update the global dictionary
    log::debug!("Updating global translation dictionary...");
    let mut translation_dictionary = TRANSLATION_DICTIONARY.write().unwrap();
    if let Some(ref mut dict) = *translation_dictionary {
        dict.dictionary.insert(Language::En, en_translations.clone());
        dict.dictionary.insert(Language::Ru, ru_translations.clone());
        // Use WASM-compatible time
        #[cfg(feature = "hydrate")]
        {
            let now = Date::now();
            dict.last_updated = std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_millis(now as u64);
            log::debug!("Updated dictionary timestamp to: {}ms", now);
        }
        #[cfg(not(feature = "hydrate"))]
        {
            dict.last_updated = std::time::SystemTime::now();
            log::debug!("Updated dictionary timestamp");
        }
        log::info!("Translation dictionary updated successfully");
    } else {
        log::error!("Failed to get write lock on translation dictionary");
        return Err(color_eyre::eyre::eyre!("Translation dictionary not initialized"));
    }
    
    Ok((en_translations, ru_translations))
}

/// Fetch translations from API endpoint
async fn fetch_translations(url: &str) -> Result<HashMap<String, String>> {
    log::debug!("Fetching translations from: {}", url);
    
    let client = reqwest::Client::new();
    log::trace!("Sending HTTP GET request to: {}", url);
    
    let response = client.get(url)
        .header("accept", "application/json")
        .send()
        .await?;
    
    let status = response.status();
    log::debug!("Received response with status: {}", status);
    
    if !status.is_success() {
        let error_text = response.text().await.unwrap_or_default();
        log::error!("Failed to fetch translations from {}: HTTP {} - {}", url, status, error_text);
        return Err(color_eyre::eyre::eyre!(
            "Failed to fetch translations: {}",
            error_text
        ));
    }
    
    let response_text = response.text().await?;
    log::trace!("Received response text ({} bytes)", response_text.len());
    
    let dictionary: HashMap<String, String> = serde_json::from_str(&response_text)
        .map_err(|e| {
            log::error!("Failed to parse JSON response from {}: {}", url, e);
            e
        })?;
    
    log::debug!("Successfully parsed {} translation entries", dictionary.len());
    Ok(dictionary)
}

/// Hash string for translation ID (exact copy from rust-shared)
fn hash_string(input: &str, key: &str) -> String {
    use hmac::{Hmac, Mac};
    use sha2::Sha256;
    
    log::trace!("hash_string: input='{}', key='{}'", input, key);
    
    let mut mac = Hmac::<Sha256>::new_from_slice(key.as_bytes())
        .expect("HMAC can take key of any size");
    mac.update(input.as_bytes());
    let result = mac.finalize().into_bytes();
    let hash = hex::encode(result);
    
    log::trace!("hash_string: '{}' + '{}' -> '{}'", input, key, hash);
    hash
}

#[macro_export]
macro_rules! make_t8r_reactive {
    () => {{
        let location = leptos_router::hooks::use_location();
        let translation_context = crate::i18n::use_translation_context();

        move |text: &'static str| {
            let translation_context = translation_context.clone();
            Memo::new(move |_| {
                let pathname = location.pathname.get();
                let current_lang = if pathname.starts_with("/ru") {
                    rust_shared::i18n::Language::Ru
                } else {
                    rust_shared::i18n::Language::En
                };

                log::info!(
                    "t8r_reactive: translating '{}' for language {:?} (pathname: '{}')",
                    text,
                    current_lang,
                    pathname
                );

                log::info!("t8r_reactive: translation_context: {:?}", translation_context);

                let translated = translation_context
                    .get_translation_with_module(text, current_lang, module_path!())
                    .unwrap_or_else(|| {
                        log::warn!("Translation not found for '{}' in language {:?}", text, current_lang);
                        text.to_string()
                    });

                log::debug!("t8r_reactive: '{}' -> '{}'", text, translated);
                translated
            })
        }
    }};
}

#[macro_export]
macro_rules! t8r {
    ($txt:expr) => {
        move || crate::make_t8r_reactive!()($txt)
    };
}

