//! Translation implementations for regex functions

use crate::utils::direct_function_translation;
use crate::TranslationRegistry;
use hamelin_lib::func::defs::{
    RegexpCount, RegexpExtract2, RegexpExtract3, RegexpExtractAll2, RegexpExtractAll3, RegexpLike,
    RegexpPosition2, RegexpPosition3, RegexpPosition4, RegexpReplace2, RegexpReplace3, RegexpSplit,
};
use hamelin_lib::sql::expression::apply::FunctionCallApply;
use hamelin_lib::sql::expression::literal::IntegerLiteral;

/// Register all regex function translations.
pub fn register(registry: &mut TranslationRegistry) {
    // regexp_count(string, pattern)
    registry.register::<RegexpCount>(direct_function_translation);

    // regexp_extract_all(string, pattern)
    registry.register::<RegexpExtractAll2>(direct_function_translation);

    // regexp_extract_all(string, pattern, group) — wrapped in TRY so OOB group returns null
    registry.register::<RegexpExtractAll3>(|func, bindings| {
        let inner = direct_function_translation(func, bindings)?;
        Ok(FunctionCallApply::with_one("try", inner).into())
    });

    // regexp_extract(string, pattern)
    registry.register::<RegexpExtract2>(direct_function_translation);

    // regexp_extract(string, pattern, group)
    registry.register::<RegexpExtract3>(direct_function_translation);

    // regexp_like(string, pattern)
    registry.register::<RegexpLike>(direct_function_translation);

    // regexp_position(string, pattern) -> GREATEST(regexp_position(string, pattern), 0)
    // Trino returns -1 for no match, but Hamelin spec says return 0
    registry.register::<RegexpPosition2>(|_, mut bindings| {
        let string = bindings.take()?.sql;
        let pattern = bindings.take()?.sql;
        let regexp_pos = FunctionCallApply::with_two("regexp_position", string, pattern);
        Ok(FunctionCallApply::with_two(
            "GREATEST",
            regexp_pos.into(),
            IntegerLiteral::from_int(0).into(),
        )
        .into())
    });

    // regexp_position(string, pattern, start) -> GREATEST(regexp_position(string, pattern, start), 0)
    registry.register::<RegexpPosition3>(|_, mut bindings| {
        let string = bindings.take()?.sql;
        let pattern = bindings.take()?.sql;
        let start = bindings.take()?.sql;
        let regexp_pos =
            FunctionCallApply::with_positional("regexp_position", vec![string, pattern, start]);
        Ok(FunctionCallApply::with_two(
            "GREATEST",
            regexp_pos.into(),
            IntegerLiteral::from_int(0).into(),
        )
        .into())
    });

    // regexp_position(string, pattern, start, occurrence) -> GREATEST(regexp_position(...), 0)
    registry.register::<RegexpPosition4>(|_, mut bindings| {
        let string = bindings.take()?.sql;
        let pattern = bindings.take()?.sql;
        let start = bindings.take()?.sql;
        let occurrence = bindings.take()?.sql;
        let regexp_pos = FunctionCallApply::with_positional(
            "regexp_position",
            vec![string, pattern, start, occurrence],
        );
        Ok(FunctionCallApply::with_two(
            "GREATEST",
            regexp_pos.into(),
            IntegerLiteral::from_int(0).into(),
        )
        .into())
    });

    // regexp_replace(string, pattern) - removes matches
    registry.register::<RegexpReplace2>(direct_function_translation);

    // regexp_replace(string, pattern, replacement)
    registry.register::<RegexpReplace3>(direct_function_translation);

    // regexp_split(string, pattern)
    registry.register::<RegexpSplit>(direct_function_translation);
}
