use crate::error::Result;
use crate::format::{self, FormatOptions, Formatter};
use crate::model::{Lang, TwineFile};
use crate::output::OutputProcessor;

pub struct AppleFormatter;

impl Formatter for AppleFormatter {
    fn name(&self) -> &'static str {
        "apple"
    }
    fn extension(&self) -> &'static str {
        ".strings"
    }
    fn default_file_name(&self) -> &'static str {
        "Localizable.strings"
    }
    fn can_handle_directory(&self, path: &str) -> bool {
        std::fs::read_dir(path).map_or(false, |entries| {
            entries.filter_map(|e| e.ok()).any(|e| {
                e.file_name()
                    .to_str()
                    .map_or(false, |n| n.ends_with(".lproj"))
            })
        })
    }
    fn detect_language(&self, path: &str) -> Option<String> {
        let re = regex::Regex::new(r"^(.+)\.lproj$").unwrap();
        for segment in path.split('/') {
            if let Some(caps) = re.captures(segment) {
                let lang = caps.get(1)?.as_str();
                return if lang == "Base" { None } else { Some(lang.to_string()) };
            }
        }
        None
    }
    fn output_dir_for_lang(&self, lang: &str) -> String {
        format!("{}.lproj", lang)
    }

    fn read(&self, content: &str, lang: &str, twine_file: &mut TwineFile) -> Result<()> {
        let kv_re = regex::Regex::new(
            r#"^\s*((?:"(?:[^"\\]|\\.)+")|(?:[^"\s=]+))\s*=\s*"((?:[^"\\]|\\.)*)""#,
        )
        .unwrap();
        let comment_re = regex::Regex::new(r"/\* (.*) \*/").unwrap();
        let mut last_comment: Option<String> = None;

        for line in content.lines() {
            if let Some(caps) = kv_re.captures(line) {
                let mut key = caps[1].to_string();
                if key.starts_with('"') && key.ends_with('"') {
                    key = key[1..key.len() - 1].to_string();
                }
                key = key.replace("\\\"", "\"");
                let value = caps[2].replace("\\\"", "\"");
                format::set_translation(twine_file, &key, lang, &value);
                if let Some(ref c) = last_comment {
                    format::set_comment(twine_file, &key, c);
                }
            }
            if let Some(caps) = comment_re.captures(line) {
                last_comment = Some(caps[1].to_string());
            } else {
                last_comment = None;
            }
        }
        Ok(())
    }

    fn format(&self, lang: &str, twine_file: &TwineFile, options: &FormatOptions) -> Result<Option<String>> {
        let processor = OutputProcessor::new(twine_file.clone(), options.clone());
        let processed = processor.process(lang);

        let mut out = format!(
            "/**\n * Apple Strings File\n * Generated by Twinex\n * Language: {}\n */\n\n",
            lang
        );
        let mut has_content = false;

        for section in &processed.sections {
            if section.definitions.is_empty() {
                continue;
            }
            if !section.name.as_str().is_empty() {
                out.push_str(&format!("/********** {} **********/\n", section.name));
            }
            for def in &section.definitions {
                if let Some(ref comment) = def.comment {
                    out.push_str(&format!("/* {} */\n", comment.replace("*/", "* /")));
                }
                let value = def.translations.get(&Lang::new(lang)).map(|s| s.as_str()).unwrap_or("");
                out.push_str(&format!("\"{}\" = \"{}\";\n", def.key, value));
                has_content = true;
            }
        }
        if has_content { Ok(Some(out)) } else { Ok(None) }
    }
}