//! FTL file parsing utilities for compile-time code generation
//!
//! This module provides utilities to parse Fluent (.ftl) files and extract
//! translation keys with their structure for automatic struct generation.

use std::collections::{BTreeMap, HashMap};
use std::fs;
use std::path::Path;

/// Represents a translation key with its metadata
#[derive(Debug, Clone, PartialEq)]
pub struct TranslationKey {
    pub key: String,
    pub value: String,
    pub section: Option<String>,
    pub subsection: Option<String>,
}

/// Represents a logical section of translation keys
#[derive(Debug, Clone)]
pub struct TranslationSection {
    pub name: String,
    pub keys: Vec<TranslationKey>,
    pub rust_struct_name: String,
    pub rust_field_name: String,
}

/// Result of parsing FTL files
#[derive(Debug, Clone)]
pub struct FtlParseResult {
    pub sections: Vec<TranslationSection>,
    pub flat_keys: Vec<TranslationKey>,
}

/// FTL file parser
pub struct FtlParser;

impl FtlParser {
    /// Parse a single FTL file and extract structured translation data
    pub fn parse_file<P: AsRef<Path>>(
        file_path: P,
    ) -> Result<FtlParseResult, Box<dyn std::error::Error>> {
        let content = fs::read_to_string(file_path)?;
        Self::parse_content(&content)
    }

    /// Parse FTL content string
    pub fn parse_content(content: &str) -> Result<FtlParseResult, Box<dyn std::error::Error>> {
        let mut keys = Vec::new();

        for line in content.lines() {
            let line = line.trim();

            // Skip comments and empty lines
            if line.is_empty() || line.starts_with('#') {
                continue;
            }

            // Parse key-value pairs
            if let Some((key, value)) = line.split_once(" = ") {
                let key = key.trim();
                let value = value.trim();

                // Extract section and subsection from key name
                let (section, subsection) = Self::extract_sections(key);

                keys.push(TranslationKey {
                    key: key.to_string(),
                    value: value.to_string(),
                    section,
                    subsection,
                });
            }
        }

        let sections = Self::group_keys_into_sections(&keys);

        Ok(FtlParseResult {
            sections,
            flat_keys: keys,
        })
    }

    /// Extract section and subsection from a translation key
    /// Examples:
    /// - "home-hero-title" -> (Some("hero"), None)
    /// - "home-services-projects-url" -> (Some("services"), Some("projects"))
    /// - "home-title" -> (None, None) - goes to root level
    fn extract_sections(key: &str) -> (Option<String>, Option<String>) {
        let parts: Vec<&str> = key.split('-').collect();

        if parts.len() < 2 {
            return (None, None);
        }

        // Skip the page prefix (e.g., "home")
        let key_parts = &parts[1..];

        match key_parts.len() {
            1 => (None, None), // Root level key
            _ => {
                // Multiple parts - first part is section, second might be subsection
                let section = key_parts[0].to_string();
                let subsection = if key_parts.len() > 1
                    && key_parts[1] != "title"
                    && key_parts[1] != "subtitle"
                    && key_parts[1] != "description"
                {
                    Some(key_parts[1].to_string())
                } else {
                    None
                };
                (Some(section), subsection)
            }
        }
    }

    /// Group translation keys into logical sections
    fn group_keys_into_sections(keys: &[TranslationKey]) -> Vec<TranslationSection> {
        let mut sections_map: BTreeMap<String, Vec<TranslationKey>> = BTreeMap::new();
        let mut root_keys = Vec::new();

        for key in keys {
            if let Some(section) = &key.section {
                sections_map
                    .entry(section.clone())
                    .or_default()
                    .push(key.clone());
            } else {
                root_keys.push(key.clone());
            }
        }

        let mut sections = Vec::new();

        // Root level keys are not grouped into a separate section
        // They are typically handled at the top level of the struct

        // Add named sections
        for (section_name, section_keys) in sections_map {
            let struct_name = Self::to_pascal_case(&format!("{section_name}_section"));
            let field_name = Self::to_snake_case(&section_name);

            sections.push(TranslationSection {
                name: section_name,
                keys: section_keys,
                rust_struct_name: struct_name,
                rust_field_name: field_name,
            });
        }

        sections
    }

    /// Convert string to PascalCase for struct names
    fn to_pascal_case(s: &str) -> String {
        s.split('_')
            .map(|word| {
                let mut chars = word.chars();
                match chars.next() {
                    None => String::new(),
                    Some(first) => {
                        first.to_uppercase().collect::<String>() + &chars.collect::<String>()
                    }
                }
            })
            .collect()
    }

    /// Convert string to snake_case for field names
    fn to_snake_case(s: &str) -> String {
        s.replace('-', "_").to_lowercase()
    }

    /// Generate Rust struct field name from translation key
    pub fn key_to_field_name(key: &str) -> String {
        // Remove page prefix and convert to snake_case
        let parts: Vec<&str> = key.split('-').collect();
        if parts.len() > 1 {
            parts[1..].join("_")
        } else {
            Self::to_snake_case(key)
        }
    }

    /// Generate Rust type for a field based on key patterns
    pub fn infer_field_type(_key: &str) -> &'static str {
        // All FTL values are strings - could be extended for specialized types
        "String"
    }
}

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

    #[test]
    fn test_section_extraction() {
        assert_eq!(
            FtlParser::extract_sections("home-hero-title"),
            (Some("hero".to_string()), None)
        );
        assert_eq!(
            FtlParser::extract_sections("home-services-projects-url"),
            (Some("services".to_string()), Some("projects".to_string()))
        );
        assert_eq!(FtlParser::extract_sections("home-title"), (None, None));
        assert_eq!(
            FtlParser::extract_sections("about-philosophy-approach"),
            (Some("philosophy".to_string()), Some("approach".to_string()))
        );
    }

    #[test]
    fn test_case_conversion() {
        assert_eq!(FtlParser::to_pascal_case("hero_section"), "HeroSection");
        assert_eq!(
            FtlParser::to_pascal_case("services_section"),
            "ServicesSection"
        );
        assert_eq!(FtlParser::to_snake_case("hero-title"), "hero_title");
        assert_eq!(
            FtlParser::to_snake_case("services-projects"),
            "services_projects"
        );
    }

    #[test]
    fn test_key_to_field_name() {
        assert_eq!(
            FtlParser::key_to_field_name("home-hero-title"),
            "hero_title"
        );
        assert_eq!(
            FtlParser::key_to_field_name("about-journey-paragraph-1"),
            "journey_paragraph_1"
        );
        assert_eq!(FtlParser::key_to_field_name("home-title"), "title");
    }

    #[test]
    fn test_parse_content() {
        let content = r#"
# Hero Section
home-hero-title = Rust Developer
home-hero-subtitle = Specializing in Rust development

# Services Section
home-services-title = How I Can Help
home-services-projects-url = /services#projects

# Root level
home-title = Home Page
"#;

        let result = FtlParser::parse_content(content).unwrap();

        assert_eq!(result.sections.len(), 2); // hero and services sections

        let hero_section = result.sections.iter().find(|s| s.name == "hero").unwrap();
        assert_eq!(hero_section.keys.len(), 2);
        assert_eq!(hero_section.rust_struct_name, "HeroSection");
        assert_eq!(hero_section.rust_field_name, "hero");

        let services_section = result
            .sections
            .iter()
            .find(|s| s.name == "services")
            .unwrap();
        assert_eq!(services_section.keys.len(), 2);
        assert_eq!(services_section.rust_struct_name, "ServicesSection");
        assert_eq!(services_section.rust_field_name, "services");
    }
}
