/// Locale — language + optional region + directionality.
///
/// Locale identifies both the language for translation lookup and the
/// region for number/date/currency formatting.

/// Text direction.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextDirection {
    LeftToRight,
    RightToLeft,
}

/// A locale identifier.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Locale {
    /// BCP 47 language tag (e.g. "en", "ar", "zh-Hant").
    pub language: String,
    /// Optional region (e.g. "US", "GB", "TW").
    pub region: Option<String>,
}

impl Locale {
    /// Create from a BCP 47 tag like "en-US" or "ar".
    pub fn new(tag: impl Into<String>) -> Self {
        let tag = tag.into();
        if let Some(idx) = tag.find('-') {
            let (lang, rest) = tag.split_at(idx);
            let region = rest.trim_start_matches('-');
            Self {
                language: lang.to_lowercase(),
                region: if region.is_empty() {
                    None
                } else {
                    Some(region.to_uppercase())
                },
            }
        } else {
            Self {
                language: tag.to_lowercase(),
                region: None,
            }
        }
    }

    /// The full BCP 47 tag (e.g. "en-US").
    pub fn tag(&self) -> String {
        match &self.region {
            Some(r) => format!("{}-{}", self.language, r),
            None => self.language.clone(),
        }
    }

    /// The text direction for this locale.
    pub fn direction(&self) -> TextDirection {
        if self.is_rtl() {
            TextDirection::RightToLeft
        } else {
            TextDirection::LeftToRight
        }
    }

    /// Whether this locale uses right-to-left script.
    pub fn is_rtl(&self) -> bool {
        // RTL language codes per Unicode CLDR
        matches!(
            self.language.as_str(),
            "ar"  // Arabic
            | "he" | "iw"  // Hebrew
            | "fa" | "per"  // Persian/Farsi
            | "ur"  // Urdu
            | "ps"  // Pashto
            | "ug"  // Uyghur
            | "yi"  // Yiddish
            | "dv"  // Maldivian/Dhivehi
            | "ku"  // Kurdish (some scripts)
            | "sd"  // Sindhi
        )
    }

    /// English (US).
    pub fn en_us() -> Self {
        Self::new("en-US")
    }

    /// English (GB).
    pub fn en_gb() -> Self {
        Self::new("en-GB")
    }

    /// Arabic (a common RTL locale).
    pub fn ar() -> Self {
        Self::new("ar")
    }

    /// Arabic (Saudi Arabia).
    pub fn ar_sa() -> Self {
        Self::new("ar-SA")
    }

    /// Spanish (Spain).
    pub fn es_es() -> Self {
        Self::new("es-ES")
    }

    /// French (France).
    pub fn fr_fr() -> Self {
        Self::new("fr-FR")
    }

    /// Japanese.
    pub fn ja() -> Self {
        Self::new("ja")
    }

    /// Chinese (Traditional).
    pub fn zh_hant() -> Self {
        Self::new("zh-Hant")
    }
}

impl std::fmt::Display for Locale {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.tag())
    }
}

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

    #[test]
    fn locale_parse_with_region() {
        let l = Locale::new("en-US");
        assert_eq!(l.language, "en");
        assert_eq!(l.region, Some("US".to_string()));
    }

    #[test]
    fn locale_parse_without_region() {
        let l = Locale::new("ja");
        assert_eq!(l.language, "ja");
        assert_eq!(l.region, None);
    }

    #[test]
    fn locale_tag_roundtrip() {
        let l = Locale::new("fr-FR");
        assert_eq!(l.tag(), "fr-FR");
    }

    #[test]
    fn arabic_is_rtl() {
        assert!(Locale::new("ar").is_rtl());
        assert!(Locale::new("ar-SA").is_rtl());
    }

    #[test]
    fn hebrew_is_rtl() {
        assert!(Locale::new("he").is_rtl());
    }

    #[test]
    fn persian_is_rtl() {
        assert!(Locale::new("fa").is_rtl());
    }

    #[test]
    fn english_is_ltr() {
        assert!(!Locale::new("en").is_rtl());
        assert_eq!(Locale::new("en-US").direction(), TextDirection::LeftToRight);
    }

    #[test]
    fn rtl_direction() {
        assert_eq!(Locale::ar().direction(), TextDirection::RightToLeft);
    }

    #[test]
    fn locale_display() {
        assert_eq!(format!("{}", Locale::en_us()), "en-US");
    }
}
