use std::sync::Arc;

use hamelin_analysis::incremental::detect_supported_strategies_for_query;
use hamelin_lib::catalog::{Catalog, CatalogProvider};
use hamelin_lib::err::{ContextualTranslationErrors, WithTranslationErrors};
use hamelin_lib::tree::ast::query::Query;
use hamelin_lib::tree::ast::ParseWithErrors;
use hamelin_lib::type_check_with_provider;
use serde::Serialize;
use tsify::Tsify;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::JsValue;

#[derive(Serialize, Tsify)]
#[tsify(into_wasm_abi)]
pub enum IncrementalEligibilityResult {
    Eligible { strategies: Vec<String> },
    NotEligible { reasons: Vec<String> },
    CompilationError(ContextualTranslationErrors),
}

#[wasm_bindgen]
pub fn check_incremental_eligibility(
    query: String,
    catalog: Catalog,
    allow_lookups: bool,
) -> Result<IncrementalEligibilityResult, JsValue> {
    let catalog_provider = Arc::new(
        CatalogProvider::try_from(catalog)
            .map_err(|e| JsValue::from_str(e.to_string().as_str()))?,
    );

    let (ast, parse_errors) = Query::parse_with_errors(query.clone());
    let WithTranslationErrors {
        output: typed_statement,
        errors: semantic_errors,
    } = type_check_with_provider::<Query>(Arc::new(ast), catalog_provider.clone());

    let mut errors = parse_errors;
    errors.extend(semantic_errors);
    if !errors.is_empty() {
        return Ok(IncrementalEligibilityResult::CompilationError(
            ContextualTranslationErrors::new(query, errors),
        ));
    }

    let result = detect_supported_strategies_for_query(
        &typed_statement,
        allow_lookups,
        catalog_provider.as_ref(),
    );

    if result.supported.is_empty() {
        Ok(IncrementalEligibilityResult::NotEligible {
            reasons: result.rejections,
        })
    } else {
        Ok(IncrementalEligibilityResult::Eligible {
            strategies: result
                .supported
                .into_iter()
                .map(|s| format!("{s:?}"))
                .collect(),
        })
    }
}
