//! Nickel-related command implementations

use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use typedialog_core::form_parser;
use typedialog_core::nickel::{
    I18nExtractor, MetadataParser, NickelCli, TemplateEngine, TomlGenerator,
};
use typedialog_core::prelude::*;

#[allow(clippy::too_many_arguments)]
pub fn nickel_to_form(
    schema: PathBuf,
    _current_data: Option<PathBuf>,
    flatten: bool,
    groups: bool,
    fragments: bool,
    _conditionals: bool,
    i18n: bool,
    output_dir: Option<PathBuf>,
) -> Result<()> {
    NickelCli::verify()?;
    let metadata = NickelCli::query(schema.as_path(), Some("inputs"))?;
    let mut schema_ir = MetadataParser::parse(metadata)?;

    if fragments {
        let markers = MetadataParser::extract_fragment_markers_from_source(schema.as_path())?;
        MetadataParser::apply_fragment_markers(&mut schema_ir, &markers);
    }

    let forms_output = if fragments && schema_ir.fields.iter().any(|f| f.fragment_marker.is_some())
    {
        TomlGenerator::generate_with_fragments(&schema_ir, flatten, groups)?
    } else {
        let form_def = TomlGenerator::generate(&schema_ir, flatten, groups)?;
        let mut single_output = HashMap::new();
        single_output.insert("form.toml".to_string(), form_def);
        single_output
    };

    let output_path = output_dir.unwrap_or_else(|| {
        if fragments && forms_output.len() > 1 {
            PathBuf::from("generated")
        } else {
            PathBuf::from(".")
        }
    });

    if forms_output.len() == 1 && output_path.as_path() == std::path::Path::new(".") {
        if let Some((_, form_def)) = forms_output.iter().next() {
            let toml_output = ::toml::to_string_pretty(form_def)
                .map_err(|e| Error::validation_failed(e.to_string()))?;
            println!("{}", toml_output);
        }
    } else {
        fs::create_dir_all(&output_path).map_err(Error::io)?;

        for (filename, form_def) in forms_output {
            let file_path = if filename.starts_with("fragments/") {
                output_path
                    .join("fragments")
                    .join(filename.strip_prefix("fragments/").unwrap())
            } else {
                output_path.join(&filename)
            };

            fs::create_dir_all(file_path.parent().unwrap()).map_err(Error::io)?;

            let toml_output = ::toml::to_string_pretty(&form_def)
                .map_err(|e| Error::validation_failed(e.to_string()))?;

            fs::write(&file_path, &toml_output).map_err(Error::io)?;
            eprintln!("  Generated: {}", file_path.display());
        }

        println!("✓ Forms generated in {}/", output_path.display());
    }

    if i18n {
        let i18n_output_dir = output_path.join("locales");
        let _i18n_mapping = I18nExtractor::extract_and_generate(&schema_ir, &i18n_output_dir)?;

        eprintln!(
            "✓ i18n translations generated in {}/",
            i18n_output_dir.display()
        );
    }

    Ok(())
}

pub fn form_to_nickel(
    form: PathBuf,
    input: PathBuf,
    output: &Option<PathBuf>,
    _validate: bool,
) -> Result<()> {
    let form_content = fs::read_to_string(&form).map_err(Error::io)?;
    let _form_def = form_parser::parse_toml(&form_content)?;

    let results: HashMap<String, serde_json::Value> = if input.extension().and_then(|s| s.to_str())
        == Some("ncl.j2")
    {
        return Err(Error::validation_failed(
            "Template-based form-to-nickel requires interactive execution. Use .json input instead."
        ));
    } else if input.extension().and_then(|s| s.to_str()) == Some("json") {
        let json_content = fs::read_to_string(&input).map_err(Error::io)?;
        serde_json::from_str(&json_content).map_err(|e| Error::validation_failed(e.to_string()))?
    } else {
        return Err(Error::validation_failed(
            "Input file must be .json or .ncl.j2",
        ));
    };

    let nickel_output = format!(
        "# Form results (JSON format for now)\n{}",
        serde_json::to_string_pretty(&results)
            .map_err(|e| Error::validation_failed(e.to_string()))?
    );

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

    Ok(())
}

pub fn nickel_template(
    template: PathBuf,
    results: PathBuf,
    output: &Option<PathBuf>,
) -> Result<()> {
    let json_content = fs::read_to_string(&results).map_err(Error::io)?;
    let values: HashMap<String, serde_json::Value> =
        serde_json::from_str(&json_content).map_err(|e| Error::validation_failed(e.to_string()))?;

    let mut engine = TemplateEngine::new();
    let nickel_output = engine.render_file(template.as_path(), &values, None)?;

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

    Ok(())
}

pub async fn nickel_roundtrip(
    input: PathBuf,
    form_path: PathBuf,
    output: PathBuf,
    ncl_template: Option<PathBuf>,
    validate: bool,
    verbose: bool,
) -> Result<()> {
    use typedialog_core::nickel::RoundtripConfig;

    if verbose {
        eprintln!("Starting Nickel roundtrip workflow with TUI backend");
    }

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

    // Create roundtrip config
    let mut config = RoundtripConfig::with_template(input, form_path, output, ncl_template);
    config.validate = validate;
    config.verbose = verbose;

    // Execute roundtrip with TUI backend
    let result = config.execute_with_backend(backend.as_mut()).await?;

    if verbose {
        eprintln!("[roundtrip] Generated {} bytes", result.output_nickel.len());
    }

    // Create and print terminal summary
    use typedialog_core::nickel::summary::RoundtripSummary;

    let summary = RoundtripSummary::from_values(
        &result.initial_values,
        &result.form_results,
        result.validation_passed,
        result.output_path.display().to_string(),
    );

    // Print terminal summary
    print!("{}", summary.render_terminal(verbose));

    println!(
        "\n✅ Configuration saved to: {}\n",
        result.output_path.display()
    );
    println!("Next steps:");
    println!(
        "  - Review the configuration: cat {}",
        result.output_path.display()
    );
    println!("  - Apply CI tools: (run your CI setup command)");
    println!("  - Re-run this script anytime to update your configuration\n");

    if let Some(passed) = result.validation_passed {
        if !passed {
            return Err(Error::validation_failed(
                "Nickel typecheck failed on output",
            ));
        }
    }

    Ok(())
}
