//! Form execution command implementation for TUI backend

use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use typedialog_core::form_parser;
use typedialog_core::helpers;
use typedialog_core::i18n::LocaleLoader;
use typedialog_core::nickel::NickelCli;
use typedialog_core::prelude::*;
use unic_langid::LanguageIdentifier;

use super::helpers::{extract_nickel_defaults, flatten_json_object};

pub async fn execute_form(
    config: PathBuf,
    defaults: Option<PathBuf>,
    format: &str,
    output_file: &Option<PathBuf>,
    cli_locale: &Option<String>,
) -> Result<()> {
    let mut form = form_parser::load_form(&config)?;

    // TUI backend uses unified elements array internally, migrate if using legacy format
    form.migrate_to_elements();

    // Extract base directory for resolving relative paths in includes
    let base_dir = config.parent().unwrap_or_else(|| std::path::Path::new("."));

    // Load default values from JSON or .ncl file if provided
    let initial_values = if let Some(defaults_path) = defaults {
        NickelCli::verify()?;
        let is_ncl = defaults_path.extension().and_then(|s| s.to_str()) == Some("ncl");

        let defaults_json: HashMap<String, serde_json::Value> = if is_ncl {
            let value = NickelCli::export(&defaults_path)?;
            match value {
                serde_json::Value::Object(map) => {
                    let extracted = extract_nickel_defaults(&map, &form.fields);
                    let flattened = flatten_json_object(&map);
                    let mut combined = extracted;
                    for (k, v) in flattened {
                        combined.entry(k).or_insert(v);
                    }
                    combined
                }
                _ => {
                    return Err(Error::validation_failed(
                        "Defaults .ncl must export to a JSON object".to_string(),
                    ))
                }
            }
        } else {
            let defaults_content = fs::read_to_string(&defaults_path).map_err(|e| {
                Error::validation_failed(format!("Failed to read defaults file: {}", e))
            })?;
            let parsed: serde_json::Value =
                serde_json::from_str(&defaults_content).map_err(|e| {
                    Error::validation_failed(format!("Failed to parse defaults JSON: {}", e))
                })?;
            match parsed {
                serde_json::Value::Object(map) => {
                    let extracted = extract_nickel_defaults(&map, &form.fields);
                    let flattened = flatten_json_object(&map);
                    let mut combined = extracted;
                    for (k, v) in flattened {
                        combined.entry(k).or_insert(v);
                    }
                    combined
                }
                _ => {
                    return Err(Error::validation_failed(
                        "Defaults must be a JSON object".to_string(),
                    ))
                }
            }
        };

        if !defaults_json.is_empty() {
            eprintln!(
                "[DEBUG] Loaded {} default field values",
                defaults_json.len()
            );
            for key in defaults_json.keys().take(5) {
                eprintln!("[DEBUG]   - {}", key);
            }
            if defaults_json.len() > 5 {
                eprintln!("[DEBUG]   ... and {} more", defaults_json.len() - 5);
            }
        }
        Some(defaults_json)
    } else {
        None
    };

    // Load I18nBundle if needed
    let i18n_bundle = if form.locale.is_some() || cli_locale.is_some() {
        let config = TypeDialogConfig::default();
        let resolver = LocaleResolver::new(config.clone());
        let form_locale = form.locale.as_deref();
        let locale = resolver.resolve(cli_locale.as_deref(), form_locale);
        let fallback_locale: LanguageIdentifier = "en-US"
            .parse()
            .map_err(|_| Error::validation_failed("Invalid fallback locale".to_string()))?;
        let loader = LocaleLoader::new(config.locales_path);
        Some(I18nBundle::new(locale, fallback_locale, &loader)?)
    } else {
        None
    };

    // Create TUI backend
    let mut backend = BackendFactory::create(BackendType::Tui)?;

    // Execute form
    let results = if let Some(ref bundle) = i18n_bundle {
        form_parser::execute_with_backend_i18n_with_defaults(
            form,
            backend.as_mut(),
            Some(bundle),
            base_dir,
            initial_values,
        )
        .await?
    } else {
        form_parser::execute_with_backend_i18n_with_defaults(
            form,
            backend.as_mut(),
            None,
            base_dir,
            initial_values,
        )
        .await?
    };

    print_results(&results, format, output_file)?;
    Ok(())
}

fn print_results(
    results: &HashMap<String, serde_json::Value>,
    format: &str,
    output_file: &Option<PathBuf>,
) -> Result<()> {
    let output = helpers::format_results(results, format)?;

    if let Some(path) = output_file {
        fs::write(path, &output).map_err(Error::io)?;
    } else {
        println!("{}", output);
    }

    Ok(())
}
