//! Manager CLI
//!
//! Interactive CLI tool for managing and generating pages in the framework.
//! Uses inquire for user prompts and integrates with the existing shared
//! infrastructure.

// Removed: use rustelo_core_types::i18n::discover_available_languages; - now
// using site structure
use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{self, Command};

use anyhow::{Context, Result};
use clap::{Arg, ArgAction, Command as ClapCommand};
use inquire::{validator::Validation, Confirm, MultiSelect, Select, Text};
use rustelo_tools::manager::dashboard::Dashboard;
use rustelo_tools::manager::editor::run_builtin_editor;
use rustelo_tools::manager::{
    find_project_root, generator::PageGenerator, PageConfig, PageTemplate,
};

fn main() {
    // Initialize env_logger for debugging
    env_logger::Builder::from_default_env()
        .filter_level(log::LevelFilter::Debug)
        .init();

    let matches = ClapCommand::new("manager")
        .version("0.1.0")
        .author("Development Team")
        .about(
            "Manager - for site management, generate new pages with templates, routes, and \
             translations.",
        )
        .arg(
            Arg::new("cli")
                .long("cli")
                .help("Launch CLI (Command Line Interface) prompt mode instead of TUI")
                .action(ArgAction::SetTrue),
        )
        .arg(
            Arg::new("language")
                .short('l')
                .long("language")
                .help("Set the language for the CLI interface")
                .value_name("LANG"),
        )
        .arg(
            Arg::new("editor")
                .short('e')
                .long("editor")
                .help("Specify editor to use (code, zed, nvim)")
                .value_name("EDITOR"),
        )
        .arg(
            Arg::new("existing")
                .short('p')
                .long("page")
                .help("Edit an existing page")
                .value_name("PAGE_NAME"),
        )
        .get_matches();

    // Extract arguments
    let use_cli = matches.get_flag("cli") || env::var("MANAGER_CLI").unwrap_or_default() == "1";
    let selected_lang = matches.get_one::<String>("language").cloned();
    let editor_override = matches.get_one::<String>("editor").cloned();
    let existing_page = matches.get_one::<String>("existing").cloned();

    let result = if let Some(page_name) = existing_page {
        // Edit existing page mode
        run_editor_mode(page_name, selected_lang, editor_override)
    } else if use_cli {
        // CLI mode explicitly requested
        run_cli(selected_lang)
    } else {
        // TUI mode is default - try TUI first, fallback to CLI if terminal setup fails
        match run_tui(selected_lang.clone()) {
            Ok(()) => Ok(()),
            Err(e)
                if e.to_string().contains("Device not configured")
                    || e.to_string().contains("terminal") =>
            {
                eprintln!("⚠️ TUI mode failed (not a terminal?), falling back to CLI mode");
                run_cli(selected_lang)
            }
            Err(e) => Err(e),
        }
    };

    if let Err(e) = result {
        eprintln!("❌ Error: {}", e);

        // Show error chain for debugging
        let mut source = e.source();
        while let Some(err) = source {
            eprintln!("   Caused by: {}", err);
            source = err.source();
        }

        process::exit(1);
    }
}

/// Discover available languages from the new site structure
fn discover_available_languages_from_site() -> Vec<String> {
    let site_root = env::var("SITE_ROOT_PATH").unwrap_or_else(|_| "site".to_string());
    let i18n_path = env::var("SITE_I18N_PATH").unwrap_or_else(|_| format!("{}/i18n", site_root));

    // Find project root and locales directory
    let project_root = match find_project_root() {
        Ok(root) => root,
        Err(_) => return vec!["en".to_string()], // Fallback to English if project root not found
    };

    let locales_dir = project_root.join(&i18n_path).join("locales");

    if !locales_dir.exists() {
        return vec!["en".to_string()]; // Fallback to English if locales
                                       // directory doesn't exist
    }

    let mut languages = Vec::new();

    if let Ok(entries) = fs::read_dir(&locales_dir) {
        for entry in entries.flatten() {
            if entry.path().is_dir() {
                if let Some(lang_code) = entry.file_name().to_str() {
                    // Check if the language has manager CLI translations
                    let cli_ftl_path = entry.path().join("manager").join("cli.ftl");
                    if cli_ftl_path.exists() {
                        languages.push(lang_code.to_string());
                    }
                }
            }
        }
    }

    // Ensure English is always available as fallback
    if !languages.contains(&"en".to_string()) {
        languages.push("en".to_string());
    }

    // Sort languages for consistent ordering
    languages.sort();
    languages
}

/// Select language interactively or use provided language
fn select_language(provided_lang: Option<String>) -> Result<String> {
    let available_languages = discover_available_languages_from_site();

    // If no languages found, fallback to English
    if available_languages.is_empty() {
        return Ok("en".to_string());
    }

    // If language was provided via command line, validate and use it
    if let Some(lang) = provided_lang {
        if available_languages.contains(&lang) {
            return Ok(lang);
        } else {
            eprintln!(
                "⚠️ Language '{}' not available. Available languages: {}",
                lang,
                available_languages.join(", ")
            );
            eprintln!(
                "💡 Use one of: {}",
                available_languages
                    .iter()
                    .map(|l| format!("--lang {}", l))
                    .collect::<Vec<_>>()
                    .join(", ")
            );
            // Continue to interactive selection
        }
    }

    // If only one language available, use it
    if available_languages.len() == 1 {
        return Ok(available_languages[0].clone());
    }

    // Interactive language selection
    let language_names: Vec<String> = available_languages
        .iter()
        .map(|code| {
            let name = match code.as_str() {
                "en" => "English",
                "es" => "Español (Spanish)",
                "fr" => "Français (French)",
                "de" => "Deutsch (German)",
                "it" => "Italiano (Italian)",
                "pt" => "Português (Portuguese)",
                "ja" => "日本語 (Japanese)",
                "zh" => "中文 (Chinese)",
                "ru" => "Русский (Russian)",
                code => code,
            };
            format!("{} ({})", name, code)
        })
        .collect();

    let default_index = available_languages
        .iter()
        .position(|lang| lang == "en")
        .unwrap_or(0);

    println!("🌍 Page Manager (for now Static Content)");
    println!("🗣️ Multiple languages available. Please select your preferred language:");

    let selection = Select::new("Language:", language_names)
        .with_starting_cursor(default_index)
        .prompt()
        .context("Failed to get language selection")?;

    // Extract language code from selection (format: "Name (code)")
    let lang_code = selection
        .split('(')
        .next_back()
        .unwrap_or("en")
        .trim_end_matches(')')
        .trim()
        .to_string();

    Ok(lang_code)
}

/// Load CLI translations from the new site structure
fn load_cli_translations(lang: &str) -> Result<HashMap<String, String>> {
    // Use new site structure environment variables
    let site_root = env::var("SITE_ROOT_PATH").unwrap_or_else(|_| "site".to_string());
    let i18n_path = env::var("SITE_I18N_PATH").unwrap_or_else(|_| format!("{}/i18n", site_root));

    // Find project root
    let project_root = find_project_root().context("Could not find project root")?;
    let locales_dir = project_root
        .join(&i18n_path)
        .join("locales")
        .join(lang)
        .join("manager");

    let mut translations = HashMap::new();

    // Load manager CLI translations from cli.ftl
    let cli_ftl_path = locales_dir.join("cli.ftl");

    if !cli_ftl_path.exists() {
        return Err(anyhow::anyhow!(
            "Manager CLI translations not found at: {}. Expected path: {}",
            cli_ftl_path.display(),
            cli_ftl_path.display()
        ));
    }

    // Read and parse the FTL file directly
    let ftl_content = fs::read_to_string(&cli_ftl_path)
        .with_context(|| format!("Failed to read FTL file: {}", cli_ftl_path.display()))?;

    // Simple FTL parsing for key = value pairs
    for line in ftl_content.lines() {
        let line = line.trim();
        if line.is_empty() || line.starts_with('#') {
            continue;
        }

        if let Some((key, value)) = line.split_once('=') {
            let key = key.trim();
            let value = value.trim();

            // Only include manager CLI specific keys (must have mgr- prefix)
            if key.starts_with("mgr-") {
                translations.insert(key.to_string(), value.to_string());
            }
        }
    }

    if translations.is_empty() {
        return Err(anyhow::anyhow!(
            "No manager CLI translations found for language: {} in file: {}",
            lang,
            cli_ftl_path.display()
        ));
    }

    Ok(translations)
}

/// Helper function to get translation with parameter substitution support
fn get_translation_with_params(
    translations: &HashMap<String, String>,
    key: &str,
) -> Option<String> {
    if let Some(value) = translations.get(key) {
        if value.starts_with("__FLUENT_MSG_WITH_PARAMS__:") {
            // This is a parameterized message, we need to load it directly from FTL
            // For now, let's provide fallback values for the known parameterized keys
            match key {
                "mgr-cli-project-root" => Some("Project root: {$path}".to_string()),
                "mgr-cli-available-languages" => {
                    Some("Available languages: {$languages}".to_string())
                }
                _ => Some(value.clone()),
            }
        } else {
            Some(value.clone())
        }
    } else {
        None
    }
}

/// Run the TUI (Text User Interface) mode with new Dashboard system
fn run_tui(provided_lang: Option<String>) -> Result<()> {
    // Get available languages without prompting
    let available_languages = discover_available_languages_from_site();

    // Auto-select language (use provided, or first available, or fallback to
    // English)
    let lang = if let Some(provided) = provided_lang {
        if available_languages.contains(&provided) {
            provided
        } else {
            available_languages
                .first()
                .unwrap_or(&"en".to_string())
                .clone()
        }
    } else {
        available_languages
            .first()
            .unwrap_or(&"en".to_string())
            .clone()
    };

    let translations = load_cli_translations(&lang).context("Failed to load CLI translations")?;

    // Find project root
    let project_root = find_project_root().context("Could not find project root")?;

    // Create dashboard instance with language information
    let mut dashboard = Dashboard::new(project_root, translations, lang, available_languages)
        .context("Failed to create dashboard")?;

    // Run dashboard
    dashboard.run().context("Dashboard execution failed")?;

    Ok(())
}

/// Run the CLI (Command Line Interface) mode
fn run_cli(provided_lang: Option<String>) -> Result<()> {
    let lang = select_language(provided_lang)?;
    let t = load_cli_translations(&lang).context("Failed to load CLI translations")?;

    // Use translations from FTL files - fail if not found
    println!(
        "🚀 {}",
        t.get("mgr-cli-title")
            .context("Missing mgr-cli-title translation")?
    );
    println!(
        "{}\n",
        t.get("mgr-cli-description")
            .context("Missing mgr-cli-description translation")?
    );

    // Find project root
    let project_root = find_project_root().with_context(|| {
        t.get("mgr-error-project-root")
            .cloned()
            .context("Missing mgr-error-project-root translation")
            .unwrap_or_else(|_| process::exit(1))
    })?;

    let project_msg = get_translation_with_params(&t, "mgr-cli-project-root")
        .map(|s| s.replace("{$path}", &project_root.display().to_string()))
        .context("Missing mgr-cli-project-root translation")?;
    println!("📁 {}", project_msg);

    // Initialize generator
    let generator = PageGenerator::new(project_root).with_context(|| {
        t.get("mgr-error-generator-init")
            .cloned()
            .context("Missing mgr-error-generator-init translation")
            .unwrap_or_else(|_| process::exit(1))
    })?;

    let languages_msg = get_translation_with_params(&t, "mgr-cli-available-languages")
        .map(|s| s.replace("{$languages}", &generator.available_languages().join(", ")))
        .context("Missing mgr-cli-available-languages translation")?;
    println!("🌐 {}\n", languages_msg);

    // Start interactive prompts
    let config = collect_page_configuration(&generator, &t)?;

    println!(
        "\n{}",
        t.get("mgr-config-summary")
            .context("Missing msg-config-summary translation")?
    );

    let name_label = t
        .get("mgr-label-name")
        .context("Missing label-name translation")?;
    let module_label = t
        .get("mgr-label-module")
        .context("Missing label-module translation")?;
    let template_label = t
        .get("mgr-label-template")
        .context("Missing label-template translation")?;
    let languages_label = t
        .get("mgr-label-languages")
        .context("Missing label-languages translation")?;
    let route_label = t
        .get("mgr-label-route")
        .context("Missing label-route translation")?;
    let scaffold_label = t
        .get("mgr-label-auto-scaffold")
        .context("Missing label-auto-scaffold translation")?;

    let yes_text = t
        .get("mgr-text-yes")
        .context("Missing text-yes translation")?;
    let no_text = t
        .get("mgr-text-no")
        .context("Missing text-no translation")?;

    println!("   {}: {}", name_label, config.name);
    println!("   {}: {}", module_label, config.module_name);
    println!(
        "   {}: {} ({})",
        template_label,
        config.template,
        config.template.description()
    );
    println!("   {}: {}", languages_label, config.languages.join(", "));
    println!("   {}: {}", route_label, config.route_path);
    println!(
        "   {}: {}",
        scaffold_label,
        if config.auto_scaffold {
            yes_text
        } else {
            no_text
        }
    );

    // Final confirmation
    let proceed = Confirm::new(
        t.get("mgr-prompt-final-confirm")
            .context("Missing prompt-confirm-generation translation")?,
    )
    .with_default(true)
    .prompt()
    .context("Failed to get confirmation")?;

    if !proceed {
        println!(
            "{}",
            t.get("mgr-status-cancelled")
                .context("Missing msg-cancelled translation")?
        );
        return Ok(());
    }

    // Generate the page
    println!(
        "\n{}",
        t.get("mgr-status-generating")
            .context("Missing msg-generating translation")?
    );
    let result = generator
        .generate_complete_page(&config)
        .context("Page generation failed")?;

    // Show results
    println!("\n{}", result.summary());

    if config.auto_scaffold {
        let next_steps = t
            .get("mgr-next-steps-with-scaffold")
            .context("Missing msg-next-steps-auto translation")?;
        println!("\n{}", next_steps.replace("{$route}", &config.route_path));
    } else {
        println!(
            "\n{}",
            t.get("mgr-next-steps-without-scaffold")
                .context("Missing msg-next-steps-manual translation")?
        );
    }

    println!(
        "\n{}",
        t.get("mgr-status-completed")
            .context("Missing msg-completed translation")?
    );

    Ok(())
}

fn collect_page_configuration(
    generator: &PageGenerator,
    t: &HashMap<String, String>,
) -> Result<PageConfig> {
    // Page name (PascalCase) - validate after input to use translations
    let prompt_text = t
        .get("mgr-prompt-page-name")
        .context("Missing mgr-prompt-page-name translation")?;
    let help_text = t
        .get("mgr-prompt-page-name-help")
        .context("Missing mgr-prompt-page-name-help translation")?;

    let name = loop {
        let input = Text::new(prompt_text)
            .with_help_message(help_text)
            .prompt()
            .context("Failed to get page name")?;

        match validate_page_name(&input, t) {
            Ok(Validation::Valid) => break input,
            Ok(Validation::Invalid(msg)) => {
                match msg {
                    inquire::validator::ErrorMessage::Custom(s) => println!("❌ {}", s),
                    inquire::validator::ErrorMessage::Default => println!("❌ Invalid input"),
                }
                continue;
            }
            Err(e) => return Err(anyhow::anyhow!("{}", e)),
        }
    };

    // Create base config
    let mut config = PageConfig::new(name).context("Failed to create page configuration")?;

    // Check for existing page
    if generator.page_exists(&config.module_name) {
        let warning_msg = t
            .get("mgr-warning-page-exists")
            .context("Missing mgr-warning-page-exists translation")?
            .replace("{$module}", &config.module_name);
        println!("⚠️  {}", warning_msg);

        let overwrite = Confirm::new(
            t.get("mgr-warning-overwrite-confirm")
                .context("Missing mgr-warning-overwrite-confirm translation")?,
        )
        .with_default(false)
        .prompt()
        .context("Failed to get overwrite confirmation")?;

        if !overwrite {
            anyhow::bail!(
                "{}",
                t.get("mgr-warning-cannot-proceed")
                    .context("Missing mgr-warning-cannot-proceed translation")?
            );
        }

        config.replace_existing = true;
    }

    // Template selection
    let templates = PageTemplate::all();
    let template_options: Vec<String> = templates
        .iter()
        .map(|tmpl| format!("{} - {}", tmpl, tmpl.description()))
        .collect();

    let selected_template = Select::new(
        t.get("mgr-prompt-template-select")
            .context("Missing mgr-prompt-template-select translation")?,
        template_options.clone(),
    )
    .with_help_message(
        t.get("mgr-prompt-template-help")
            .context("Missing mgr-prompt-template-help translation")?,
    )
    .prompt()
    .context("Failed to get template selection")?;

    // Find the template index from the selected string
    let template_index = template_options
        .iter()
        .position(|t| *t == selected_template)
        .expect("Selected template should exist in options");

    config.template = templates[template_index].clone();

    // Language selection
    let available_languages = generator.available_languages().to_vec();
    let selected_languages = if available_languages.len() > 1 {
        MultiSelect::new(
            t.get("mgr-prompt-languages-select")
                .context("Missing mgr-prompt-languages-select translation")?,
            available_languages.clone(),
        )
        .with_default(&[0, 1]) // Default to first two languages
        .with_help_message(
            t.get("mgr-prompt-languages-help")
                .context("Missing mgr-prompt-languages-help translation")?,
        )
        .prompt()
        .context("Failed to get language selection")?
    } else {
        available_languages.clone()
    };

    if selected_languages.is_empty() {
        anyhow::bail!(
            "{}",
            t.get("mgr-error-at-least-one-language")
                .context("Missing mgr-error-at-least-one-language translation")?
        );
    }

    config.languages = selected_languages;

    // Route path (with smart default) - validate after input to use translations
    let default_route = config.route_path.clone();
    let route_prompt = t
        .get("mgr-prompt-route-path")
        .context("Missing mgr-prompt-route-path translation")?;
    let route_help = t
        .get("mgr-prompt-route-path-help")
        .context("Missing mgr-prompt-route-path-help translation")?;

    let route_path = loop {
        let input = Text::new(route_prompt)
            .with_default(&default_route)
            .with_help_message(route_help)
            .prompt()
            .context("Failed to get route path")?;

        match validate_route_path(&input, t) {
            Ok(Validation::Valid) => break input,
            Ok(Validation::Invalid(msg)) => {
                match msg {
                    inquire::validator::ErrorMessage::Custom(s) => println!("❌ {}", s),
                    inquire::validator::ErrorMessage::Default => println!("❌ Invalid input"),
                }
                continue;
            }
            Err(e) => return Err(anyhow::anyhow!("{}", e)),
        }
    };

    config.route_path = route_path;

    // Auto-scaffold option
    let auto_scaffold = Confirm::new(
        t.get("mgr-prompt-auto-scaffold")
            .context("Missing prompt-auto-scaffold translation")?,
    )
    .with_default(true)
    .with_help_message(
        t.get("mgr-prompt-auto-scaffold-help")
            .context("Missing prompt-auto-scaffold-help translation")?,
    )
    .prompt()
    .context("Failed to get auto-scaffold preference")?;

    config.auto_scaffold = auto_scaffold;

    // Priority (advanced option)
    let set_priority = Confirm::new(
        t.get("mgr-prompt-custom-priority")
            .context("Missing prompt-priority translation")?,
    )
    .with_default(false)
    .with_help_message(
        t.get("mgr-prompt-custom-priority-help")
            .context("Missing prompt-priority-help translation")?,
    )
    .prompt()
    .context("Failed to get priority preference")?;

    if set_priority {
        let priority_prompt = t
            .get("mgr-prompt-priority-value")
            .context("Missing mgr-prompt-priority-value translation")?;

        let priority_str = loop {
            let input = Text::new(priority_prompt)
                .with_default("1.0")
                .prompt()
                .context("Failed to get route priority")?;

            match validate_priority(&input, t) {
                Ok(Validation::Valid) => break input,
                Ok(Validation::Invalid(msg)) => {
                    match msg {
                        inquire::validator::ErrorMessage::Custom(s) => println!("❌ {}", s),
                        inquire::validator::ErrorMessage::Default => println!("❌ Invalid input"),
                    }
                    continue;
                }
                Err(e) => return Err(anyhow::anyhow!("{}", e)),
            }
        };

        config.priority = priority_str.parse().context("Invalid priority value")?;
    }

    // Custom i18n patterns (advanced option)
    let custom_patterns = Confirm::new(
        t.get("mgr-prompt-custom-patterns")
            .context("Missing prompt-i18n-patterns translation")?,
    )
    .with_default(false)
    .with_help_message(
        t.get("mgr-prompt-custom-patterns-help")
            .context("Missing prompt-i18n-patterns-help translation")?,
    )
    .prompt()
    .context("Failed to get i18n patterns preference")?;

    if custom_patterns {
        let patterns_str = Text::new(
            t.get("mgr-prompt-patterns-value")
                .context("Missing prompt-i18n-patterns-value translation")?,
        )
        .with_default(&config.i18n_patterns.join(", "))
        .with_help_message(
            t.get("mgr-prompt-patterns-example")
                .context("Missing prompt-i18n-patterns-example translation")?,
        )
        .prompt()
        .context("Failed to get i18n patterns")?;

        config.i18n_patterns = patterns_str
            .split(',')
            .map(|s| s.trim().to_string())
            .filter(|s| !s.is_empty())
            .collect();

        if config.i18n_patterns.is_empty() {
            config.i18n_patterns = vec![format!("{}-", config.module_name.replace('_', "-"))];
        }
    }

    Ok(config)
}

// Validation functions using translations (no hardcoded strings)
fn validate_page_name(
    name: &str,
    t: &HashMap<String, String>,
) -> Result<Validation, Box<dyn std::error::Error + Send + Sync + 'static>> {
    if name.is_empty() {
        let msg = t
            .get("mgr-validation-name-empty")
            .ok_or("Missing mgr-validation-name-empty translation")?;
        return Ok(Validation::Invalid(msg.clone().into()));
    }

    if !name.chars().next().unwrap_or('a').is_uppercase() {
        let msg = t
            .get("mgr-validation-name-case")
            .ok_or("Missing mgr-validation-name-case translation")?;
        return Ok(Validation::Invalid(msg.clone().into()));
    }

    if !name.chars().all(|c| c.is_ascii_alphanumeric()) {
        let msg = t
            .get("mgr-validation-name-chars")
            .ok_or("Missing mgr-validation-name-chars translation")?;
        return Ok(Validation::Invalid(msg.clone().into()));
    }

    if name.len() > 50 {
        let msg = t
            .get("mgr-validation-name-length")
            .ok_or("Missing mgr-validation-name-length translation")?;
        return Ok(Validation::Invalid(msg.clone().into()));
    }

    // Check for reserved names
    let reserved_names = ["Component", "Page", "Router", "App", "Layout"];
    if reserved_names.contains(&name) {
        let msg = t
            .get("mgr-validation-name-reserved")
            .ok_or("Missing mgr-validation-name-reserved translation")?
            .replace("{$name}", name);
        return Ok(Validation::Invalid(msg.into()));
    }

    Ok(Validation::Valid)
}

fn validate_route_path(
    path: &str,
    t: &HashMap<String, String>,
) -> Result<Validation, Box<dyn std::error::Error + Send + Sync + 'static>> {
    if path.is_empty() {
        let msg = t
            .get("mgr-validation-path-empty")
            .ok_or("Missing mgr-validation-path-empty translation")?;
        return Ok(Validation::Invalid(msg.clone().into()));
    }

    if !path.starts_with('/') {
        let msg = t
            .get("mgr-validation-path-start")
            .ok_or("Missing mgr-validation-path-start translation")?;
        return Ok(Validation::Invalid(msg.clone().into()));
    }

    if path != "/" && path.ends_with('/') {
        let msg = t
            .get("mgr-validation-path-end")
            .ok_or("Missing mgr-validation-path-end translation")?;
        return Ok(Validation::Invalid(msg.clone().into()));
    }

    if path.contains("//") {
        let msg = t
            .get("mgr-validation-path-consecutive")
            .ok_or("Missing mgr-validation-path-consecutive translation")?;
        return Ok(Validation::Invalid(msg.clone().into()));
    }

    // Check for invalid characters
    for char in path.chars() {
        if !char.is_ascii() || char.is_ascii_whitespace() {
            let msg = t
                .get("mgr-validation-path-chars")
                .ok_or("Missing mgr-validation-path-chars translation")?;
            return Ok(Validation::Invalid(msg.clone().into()));
        }
    }

    // Check for reserved paths
    let reserved_paths = ["/api", "/assets", "/pkg", "/static"];
    if reserved_paths
        .iter()
        .any(|&reserved| path.starts_with(reserved))
    {
        let msg = t
            .get("mgr-validation-path-reserved")
            .ok_or("Missing mgr-validation-path-reserved translation")?
            .replace("{$path}", path);
        return Ok(Validation::Invalid(msg.into()));
    }

    Ok(Validation::Valid)
}

fn validate_priority(
    priority: &str,
    t: &HashMap<String, String>,
) -> Result<Validation, Box<dyn std::error::Error + Send + Sync + 'static>> {
    match priority.parse::<f64>() {
        Ok(p) if (0.1..=10.0).contains(&p) => Ok(Validation::Valid),
        Ok(_) => {
            let msg = t
                .get("mgr-validation-priority-range")
                .ok_or("Missing mgr-validation-priority-range translation")?;
            Ok(Validation::Invalid(msg.clone().into()))
        }
        Err(_) => {
            let msg = t
                .get("mgr-validation-priority-number")
                .ok_or("Missing mgr-validation-priority-number translation")?;
            Ok(Validation::Invalid(msg.clone().into()))
        }
    }
}

/// Run editor mode for existing pages
fn run_editor_mode(
    page_name: String,
    provided_lang: Option<String>,
    editor_override: Option<String>,
) -> Result<()> {
    let lang = select_language(provided_lang)?;
    let t = load_cli_translations(&lang).context("Failed to load CLI translations")?;

    // Find project root
    let project_root = find_project_root().context("Could not find project root")?;

    println!(
        "🔧 {}",
        t.get("mgr-editor-title")
            .unwrap_or(&"Page Editor".to_string())
    );
    println!("📄 Editing page: {}\n", page_name);

    // Find existing page directory
    let page_dir = find_page_directory(&project_root, &page_name)?;
    if !page_dir.exists() {
        anyhow::bail!("Page '{}' not found in crates/pages/src/", page_name);
    }

    // Discover all files related to this page
    let page_files = discover_page_files(&project_root, &page_name)?;

    if page_files.is_empty() {
        anyhow::bail!("No files found for page '{}'", page_name);
    }

    // Select editor to use
    let editor = select_editor(editor_override)?;

    // Ask user preference for multi-file editing
    let edit_all_by_default = if editor != "builtin" && supports_multi_files(&editor) {
        // For multi-tab editors, ask if user wants to edit all files at once by default
        let prompt_text = t
            .get("mgr-editor-open-all-prompt")
            .cloned()
            .unwrap_or_else(|| {
                "📂 Open all page files at once? (recommended for VS Code, Zed)".to_string()
            });
        let help_text = t
            .get("mgr-editor-open-all-help")
            .cloned()
            .unwrap_or_else(|| {
                "This opens all related files (routes, components, translations) in tabs"
                    .to_string()
            });

        Confirm::new(&prompt_text)
            .with_default(true)
            .with_help_message(&help_text)
            .prompt()
            .context("Failed to get edit preference")?
    } else {
        false // Built-in editor opens files one by one
    };

    if edit_all_by_default {
        // Open all files immediately
        let paths: Vec<PathBuf> = page_files.iter().map(|f| f.path.clone()).collect();
        open_files_in_editor(&editor, &paths)?;
        let success_msg = t
            .get("mgr-editor-opened-all-files")
            .unwrap_or(&"✅ Opened all {count} files in {editor}".to_string())
            .replace("{count}", &page_files.len().to_string())
            .replace("{editor}", &editor);
        println!("{}", success_msg);
        return Ok(());
    }

    // File management loop
    loop {
        let files_header = t
            .get("mgr-editor-files-header")
            .unwrap_or(&"📁 Files for page '{page}':".to_string())
            .replace("{page}", &page_name);
        println!("\n{}", files_header);

        for (i, file_info) in page_files.iter().enumerate() {
            println!(
                "  {}. {} ({})",
                i + 1,
                file_info.display_name,
                file_info.file_type
            );
        }

        let file_options: Vec<String> = page_files
            .iter()
            .enumerate()
            .map(|(i, file)| format!("{}. {} ({})", i + 1, file.display_name, file.file_type))
            .collect();

        let mut actions = vec![
            t.get("mgr-editor-action-edit-selected")
                .cloned()
                .unwrap_or_else(|| "📝 Edit selected file".to_string()),
            t.get("mgr-editor-action-open-all")
                .cloned()
                .unwrap_or_else(|| "📂 Open all files in editor".to_string()),
        ];

        // Add different options based on editor capabilities
        if editor != "builtin" && supports_multi_files(&editor) {
            let open_folder_text = t
                .get("mgr-editor-action-open-folder")
                .cloned()
                .unwrap_or_else(|| "🖥️ Open project folder in editor".to_string());
            actions.push(open_folder_text);
        }

        actions.extend(vec![
            t.get("mgr-editor-action-add-route")
                .cloned()
                .unwrap_or_else(|| "➕ Add new route".to_string()),
            t.get("mgr-editor-action-add-translation")
                .cloned()
                .unwrap_or_else(|| "🌐 Add new translation".to_string()),
            t.get("mgr-editor-action-refresh")
                .cloned()
                .unwrap_or_else(|| "🔄 Refresh file list".to_string()),
            t.get("mgr-editor-action-exit")
                .cloned()
                .unwrap_or_else(|| "❌ Exit".to_string()),
        ]);

        let action_prompt = t
            .get("mgr-editor-action-prompt")
            .cloned()
            .unwrap_or_else(|| "What would you like to do?".to_string());
        let action = Select::new(&action_prompt, actions)
            .prompt()
            .context("Failed to get action selection")?;

        match action.as_str() {
            s if s.starts_with("📝") => {
                // Edit specific file
                let file_select_prompt = t
                    .get("mgr-editor-select-file-prompt")
                    .cloned()
                    .unwrap_or_else(|| "Select file to edit:".to_string());
                let file_selection = Select::new(&file_select_prompt, file_options.clone())
                    .prompt()
                    .context("Failed to get file selection")?;

                let file_index = file_selection
                    .chars()
                    .next()
                    .and_then(|c| c.to_digit(10))
                    .map(|d| d as usize - 1)
                    .context("Invalid file selection")?;

                if let Some(file_info) = page_files.get(file_index) {
                    open_file_in_editor(&editor, &file_info.path)?;
                }
            }
            s if s.starts_with("📂") => {
                // Open all files
                let paths: Vec<PathBuf> = page_files.iter().map(|f| f.path.clone()).collect();
                open_files_in_editor(&editor, &paths)?;
            }
            s if s.starts_with("🖥️") => {
                // Open project folder in editor
                open_project_folder_in_editor(&editor, &project_root)?;
            }
            s if s.starts_with("➕") => {
                // Add new route - TODO: implement route addition
                let not_implemented = t
                    .get("mgr-editor-route-not-implemented")
                    .cloned()
                    .unwrap_or_else(|| "🚧 Route addition not yet implemented".to_string());
                println!("{}", not_implemented);
            }
            s if s.starts_with("🌐") => {
                // Add new translation - TODO: implement translation addition
                let not_implemented = t
                    .get("mgr-editor-translation-not-implemented")
                    .cloned()
                    .unwrap_or_else(|| "🚧 Translation addition not yet implemented".to_string());
                println!("{}", not_implemented);
            }
            s if s.starts_with("🔄") => {
                // Refresh files (just continue loop)
                let refreshing_msg = t
                    .get("mgr-editor-refreshing")
                    .cloned()
                    .unwrap_or_else(|| "🔄 Refreshing file list...".to_string());
                println!("{}", refreshing_msg);
                continue;
            }
            _ => {
                // Exit
                let exit_msg = t
                    .get("mgr-editor-exiting")
                    .cloned()
                    .unwrap_or_else(|| "👋 Exiting page editor".to_string());
                println!("{}", exit_msg);
                break;
            }
        }
    }

    Ok(())
}

/// Select editor to use (priority: CLI arg > env var > prompt)
fn select_editor(editor_override: Option<String>) -> Result<String> {
    // 1. Use CLI argument if provided
    if let Some(editor) = editor_override {
        return Ok(editor);
    }

    // 2. Use environment variable if set
    if let Ok(env_editor) = env::var("MANAGER_EDITOR") {
        if !env_editor.is_empty() {
            return Ok(env_editor);
        }
    }

    // 3. Try standard EDITOR environment variable
    if let Ok(system_editor) = env::var("EDITOR") {
        if !system_editor.is_empty() {
            return Ok(system_editor);
        }
    }

    // 4. Prompt user to select
    println!("🔧 No editor configured. Please select your preferred editor:");
    println!("💡 Tip: Set MANAGER_EDITOR environment variable to skip this prompt");
    println!("💡 Tip: Set PAGE_EDITORS environment variable to customize available editors");

    let editors = get_available_editors();

    let selection = Select::new("Editor:", editors)
        .with_starting_cursor(0) // Default to Built-in Editor
        .prompt()
        .context("Failed to get editor selection")?;

    // Extract editor command from selection
    let editor_cmd = selection.split(' ').next().unwrap_or("builtin").to_string();

    println!("💡 Selected: {}. To avoid this prompt, run:", editor_cmd);
    println!("   export MANAGER_EDITOR={}", editor_cmd);
    println!("   # or use --editor {} flag", editor_cmd);

    Ok(editor_cmd)
}

/// Get available editors from environment variable or use defaults
fn get_available_editors() -> Vec<String> {
    // Default editor configurations with descriptions
    let default_editors = vec![
        ("builtin", "Built-in Editor"),
        ("code", "Visual Studio Code"),
        ("zed", "Zed Editor"),
        ("vim", "Vim"),
        ("nvim", "Neovim"),
        ("nano", "Nano"),
        ("emacs", "Emacs"),
        ("subl", "Sublime Text"),
        ("atom", "Atom"),
        ("cursor", "Cursor"),
        ("fleet", "Fleet"),
        ("webstorm", "WebStorm"),
        ("idea", "IntelliJ IDEA"),
    ];

    // Check if custom editor list is provided
    if let Ok(page_editors) = env::var("PAGE_EDITORS") {
        if !page_editors.is_empty() {
            let custom_editors: Vec<String> = page_editors
                .split(',')
                .filter_map(|editor| {
                    let editor = editor.trim();
                    if editor.is_empty() {
                        return None;
                    }

                    // Try to find description for known editors
                    let description = default_editors
                        .iter()
                        .find(|(name, _)| *name == editor)
                        .map(|(_, desc)| *desc)
                        .unwrap_or("Custom Editor");

                    Some(format!("{} ({})", editor, description))
                })
                .collect();

            if !custom_editors.is_empty() {
                return custom_editors;
            }
        }
    }

    // Use default editors
    default_editors
        .into_iter()
        .map(|(name, desc)| format!("{} ({})", name, desc))
        .collect()
}

/// Check if editor supports opening multiple files at once
fn supports_multi_files(editor: &str) -> bool {
    // Default editors that support multiple files
    let default_multi_editors = vec![
        "code", "zed", "subl", "atom", "cursor", "fleet", "webstorm", "idea", "vim", "nvim",
        "emacs",
    ];

    // Check if custom multi-editor list is provided
    if let Ok(page_multi_editors) = env::var("PAGE_MULTI_EDITOR") {
        if !page_multi_editors.is_empty() {
            let custom_multi_editors: Vec<&str> = page_multi_editors
                .split(',')
                .map(|editor| editor.trim())
                .filter(|editor| !editor.is_empty())
                .collect();

            return custom_multi_editors.contains(&editor);
        }
    }

    // Use default list
    default_multi_editors.contains(&editor)
}

/// Find the directory for a page in crates/pages/src
fn find_page_directory(project_root: &Path, page_name: &str) -> Result<PathBuf> {
    let pages_dir = project_root.join("crates").join("pages").join("src");

    // Try direct match first (exact directory name)
    let direct_path = pages_dir.join(page_name);
    if direct_path.exists() {
        return Ok(direct_path);
    }

    // Try case-insensitive search
    if let Ok(entries) = fs::read_dir(&pages_dir) {
        for entry in entries.flatten() {
            if entry.file_name().to_string_lossy().to_lowercase() == page_name.to_lowercase() {
                return Ok(entry.path());
            }
        }
    }

    Ok(direct_path) // Return even if doesn't exist - will be handled by caller
}

#[derive(Debug, Clone)]
struct PageFileInfo {
    path: PathBuf,
    display_name: String,
    file_type: String,
}

/// Discover all files related to a page
fn discover_page_files(project_root: &Path, page_name: &str) -> Result<Vec<PageFileInfo>> {
    let mut files = Vec::new();

    // 1. Page component files in crates/pages/src/{page_name}/
    let page_dir = find_page_directory(project_root, page_name)?;
    if page_dir.exists() {
        if let Ok(entries) = fs::read_dir(&page_dir) {
            for entry in entries.flatten() {
                let path = entry.path();
                if path.is_file() {
                    let file_name = path
                        .file_name()
                        .and_then(|n| n.to_str())
                        .unwrap_or("unknown")
                        .to_string();

                    let file_type = match file_name.as_str() {
                        "mod.rs" => "Module definition",
                        "unified.rs" => "Unified component",
                        "client.rs" => "Client component",
                        "ssr.rs" => "SSR component",
                        _ => "Component file",
                    };

                    files.push(PageFileInfo {
                        path,
                        display_name: format!("crates/pages/src/{}/{}", page_name, file_name),
                        file_type: file_type.to_string(),
                    });
                }
            }
        }
    }

    // 2. Route configuration files
    let routes_dir = project_root.join("content").join("routes");
    if let Ok(entries) = fs::read_dir(&routes_dir) {
        for entry in entries.flatten() {
            let path = entry.path();
            if path.extension().is_some_and(|ext| ext == "toml") {
                // Check if this route file mentions our page
                if let Ok(content) = fs::read_to_string(&path) {
                    if content.contains(&format!("component = \"{}\"", page_name))
                        || content.contains(&format!("component=\"{}\"", page_name))
                    {
                        let file_name = path
                            .file_name()
                            .and_then(|n| n.to_str())
                            .unwrap_or("unknown")
                            .to_string();

                        files.push(PageFileInfo {
                            path,
                            display_name: format!("content/routes/{}", file_name),
                            file_type: "Route configuration".to_string(),
                        });
                    }
                }
            }
        }
    }

    // 3. Translation files (FTL files in content/locales/)
    let locales_dir = project_root.join("content").join("locales");
    if let Ok(lang_entries) = fs::read_dir(&locales_dir) {
        for lang_entry in lang_entries.flatten() {
            if lang_entry.path().is_dir() {
                let lang_dir = lang_entry.path();
                if let Ok(ftl_entries) = fs::read_dir(&lang_dir) {
                    for ftl_entry in ftl_entries.flatten() {
                        let path = ftl_entry.path();
                        if path.extension().is_some_and(|ext| ext == "ftl") {
                            // Check if this FTL file has keys for our page
                            if let Ok(content) = fs::read_to_string(&path) {
                                let page_key_prefix = format!("{}-", page_name.replace('_', "-"));
                                if content.contains(&page_key_prefix) {
                                    let lang_code = lang_dir
                                        .file_name()
                                        .and_then(|n| n.to_str())
                                        .unwrap_or("unknown");
                                    let file_name = path
                                        .file_name()
                                        .and_then(|n| n.to_str())
                                        .unwrap_or("unknown")
                                        .to_string();
                                    let lang_code = lang_code.to_string();

                                    files.push(PageFileInfo {
                                        path,
                                        display_name: format!(
                                            "content/locales/{}/{}",
                                            lang_code, file_name
                                        ),
                                        file_type: format!("Translation ({})", lang_code),
                                    });
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    Ok(files)
}

/// Open a single file in the selected editor
fn open_file_in_editor(editor: &str, file_path: &PathBuf) -> Result<()> {
    if editor == "builtin" {
        // Use built-in editor
        println!("🚀 Opening {} in built-in editor...", file_path.display());
        let translations = HashMap::new(); // TODO: Pass proper translations
        return run_builtin_editor(file_path.clone(), translations);
    }

    println!("🚀 Opening {} in {}...", file_path.display(), editor);

    let mut cmd = Command::new(editor);
    cmd.arg(file_path);

    // For some editors, we want to wait for them to close
    match editor {
        "vim" | "nvim" | "nano" | "emacs" => {
            let status = cmd
                .status()
                .with_context(|| format!("Failed to launch editor: {}", editor))?;

            if !status.success() {
                anyhow::bail!("Editor exited with error code: {}", status);
            }
        }
        _ => {
            // For GUI editors, spawn and don't wait
            cmd.spawn()
                .with_context(|| format!("Failed to launch editor: {}", editor))?;
        }
    }

    Ok(())
}

/// Open multiple files in the selected editor
fn open_files_in_editor(editor: &str, file_paths: &[PathBuf]) -> Result<()> {
    if editor == "builtin" {
        // Use built-in editor - open files one by one
        let translations = HashMap::new(); // TODO: Pass proper translations
        for file_path in file_paths {
            println!("🚀 Opening {} in built-in editor...", file_path.display());
            run_builtin_editor(file_path.clone(), translations.clone())?;
        }
        return Ok(());
    }

    println!("🚀 Opening {} files in {}...", file_paths.len(), editor);

    let mut cmd = Command::new(editor);
    for path in file_paths {
        cmd.arg(path);
    }

    match editor {
        "vim" | "nvim" | "nano" | "emacs" => {
            let status = cmd
                .status()
                .with_context(|| format!("Failed to launch editor: {}", editor))?;

            if !status.success() {
                anyhow::bail!("Editor exited with error code: {}", status);
            }
        }
        _ => {
            cmd.spawn()
                .with_context(|| format!("Failed to launch editor: {}", editor))?;
        }
    }

    Ok(())
}

/// Open project folder in the selected editor
fn open_project_folder_in_editor(editor: &str, project_root: &PathBuf) -> Result<()> {
    if editor == "builtin" {
        println!("⚠️ Built-in editor doesn't support opening project folders");
        return Ok(());
    }

    println!("🚀 Opening project folder in {}...", editor);

    let mut cmd = Command::new(editor);
    cmd.arg(project_root);

    match editor {
        "vim" | "nvim" | "nano" | "emacs" => {
            // Terminal editors can't really open folders, open the directory
            let status = cmd
                .status()
                .with_context(|| format!("Failed to launch editor: {}", editor))?;

            if !status.success() {
                anyhow::bail!("Editor exited with error code: {}", status);
            }
        }
        _ => {
            // GUI editors can open folders/projects
            cmd.spawn()
                .with_context(|| format!("Failed to launch editor: {}", editor))?;
        }
    }

    Ok(())
}
