use super::compare::wasm_compare_document;
use crate::compare::sexp;
use crate::context::GlobalSettings;
use crate::parser::parse_with_settings;
use crate::util::emacs_parse_anonymous_org_document;
use crate::util::foreground_color;
use crate::util::print_versions;
use crate::util::reset_color;
use crate::wasm::ToWasm;
use crate::wasm::ToWasmContext;

pub async fn wasm_run_anonymous_compare<P: AsRef<str>>(
    org_contents: P,
) -> Result<bool, Box<dyn std::error::Error>> {
    wasm_run_anonymous_compare_with_settings(org_contents, &GlobalSettings::default(), false).await
}

pub async fn wasm_run_anonymous_compare_with_settings<'g, 's, P: AsRef<str>>(
    org_contents: P,
    global_settings: &GlobalSettings<'g, 's>,
    silent: bool,
) -> Result<bool, Box<dyn std::error::Error>> {
    // TODO: This is a work-around to pretend that dos line endings do not exist. It would be better to handle the difference in line endings.
    let org_contents = org_contents.as_ref().replace("\r\n", "\n");
    let org_contents = org_contents.as_str();
    if !silent {
        print_versions().await?;
    }
    let rust_parsed = parse_with_settings(org_contents, global_settings)?;
    let to_wasm_context = ToWasmContext::new(org_contents);
    let wasm_parsed = rust_parsed
        .to_wasm(to_wasm_context)
        .map_err(|_e| "Failed to convert to wasm.")?;
    let org_sexp = emacs_parse_anonymous_org_document(org_contents, global_settings).await?;
    let (_remaining, parsed_sexp) = sexp(org_sexp.as_str()).map_err(|e| e.to_string())?;

    if !silent {
        println!("{}\n\n\n", org_contents);
        println!("{}", org_sexp);
        println!("{:#?}", rust_parsed);
        println!("{}", serde_json::to_string(&wasm_parsed)?);
    }

    // We do the diffing after printing out both parsed forms in case the diffing panics
    let diff_result = wasm_compare_document(org_contents, &parsed_sexp, wasm_parsed)?;
    if !silent {
        diff_result.print(org_contents)?;
    }

    if diff_result.is_bad() {
        return Ok(false);
    } else if !silent {
        println!(
            "{color}Entire document passes.{reset}",
            color = foreground_color(0, 255, 0),
            reset = reset_color(),
        );
    }

    Ok(true)
}