use std::sync::{Arc, RwLock};
use std::cell::RefCell;
use crate::i18n::{Language, Uniq, trans};

/// Generic language context that can be used across different environments
/// This provides a thread-safe way to manage current language state
#[derive(Clone)]
pub struct LanguageContext {
    current_language: Arc<RwLock<Language>>,
    listeners: Arc<RwLock<Vec<Box<dyn Fn(Language) + Send + Sync>>>>,
}

impl std::fmt::Debug for LanguageContext {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("LanguageContext")
            .field("current_language", &self.current_language)
            .field("listeners", &format!("{} listeners", self.listeners.read().unwrap().len()))
            .finish()
    }
}

impl LanguageContext {
    /// Create a new language context with default language (English)
    pub fn new() -> Self {
        Self {
            current_language: Arc::new(RwLock::new(Language::En)),
            listeners: Arc::new(RwLock::new(Vec::new())),
        }
    }

    /// Create a new language context with specified default language
    pub fn with_language(language: Language) -> Self {
        Self {
            current_language: Arc::new(RwLock::new(language)),
            listeners: Arc::new(RwLock::new(Vec::new())),
        }
    }

    /// Get the current language
    pub fn get_current_language(&self) -> Language {
        *self.current_language.read().unwrap()
    }

    /// Set the current language and notify listeners
    pub fn set_language(&self, language: Language) {
        {
            let mut current = self.current_language.write().unwrap();
            *current = language;
        }
        
        let listeners = self.listeners.read().unwrap();
        for listener in listeners.iter() {
            listener(language);
        }
    }

    /// Add a listener that will be called when language changes
    pub fn add_listener<F>(&self, listener: F) 
    where 
        F: Fn(Language) + Send + Sync + 'static 
    {
        let mut listeners = self.listeners.write().unwrap();
        listeners.push(Box::new(listener));
    }

    /// Translate text using the current language context
    pub fn translate(&self, text: impl Into<String>, uniq: Uniq, text_language: Language) -> &'static str {
        let current_lang = self.get_current_language();
        trans(text, uniq, text_language, &current_lang)
    }
}

impl Default for LanguageContext {
    fn default() -> Self {
        Self::new()
    }
}

thread_local! {
    static CURRENT_CONTEXT: RefCell<Option<LanguageContext>> = RefCell::new(None);
}

/// Set the current language context for this thread
pub fn provide_language_context(context: LanguageContext) {
    CURRENT_CONTEXT.with(|ctx| {
        *ctx.borrow_mut() = Some(context);
    });
}

/// Get the current language context for this thread
pub fn use_language_context() -> Option<LanguageContext> {
    CURRENT_CONTEXT.with(|ctx| ctx.borrow().clone())
}

/// Get the current language from the thread-local context
/// Falls back to English if no context is set
pub fn get_current_language() -> Language {
    CURRENT_CONTEXT.with(|ctx| {
        ctx.borrow()
            .as_ref()
            .map(|context| context.get_current_language())
            .unwrap_or(Language::En)
    })
}

/// Set the current language in the thread-local context
pub fn set_current_language(language: Language) {
    CURRENT_CONTEXT.with(|ctx| {
        if let Some(context) = ctx.borrow().as_ref() {
            context.set_language(language);
        }
    });
}
