use crate::ast::{Expr, RoutineParam};
use crate::catalog::{Catalog, TableDef, TableTypeDef};
use crate::error::DbError;

pub(crate) fn find_param_def<'a>(
    params: &'a [RoutineParam],
    name: &str,
) -> Option<&'a RoutineParam> {
    params.iter().find(|p| p.name.eq_ignore_ascii_case(name))
}

pub(crate) fn resolve_table_identifier(expr: &Expr) -> Result<&str, DbError> {
    match expr {
        Expr::Identifier(name) => Ok(name.as_str()),
        _ => Err(DbError::Execution(
            "table-valued parameter arguments must be table variables or temp-table identifiers"
                .into(),
        )),
    }
}

pub(crate) fn validate_table_matches_type(
    _catalog: &dyn Catalog,
    table: &TableDef,
    tdef: &TableTypeDef,
) -> Result<(), DbError> {
    if table.columns.len() != tdef.columns.len() {
        return Err(DbError::Execution(format!(
            "TVP type mismatch for '{}.{}': expected {} columns, got {}",
            tdef.schema,
            tdef.name,
            tdef.columns.len(),
            table.columns.len()
        )));
    }
    for (idx, (actual, expected)) in table.columns.iter().zip(tdef.columns.iter()).enumerate() {
        let expected_ty =
            crate::executor::type_mapping::data_type_spec_to_runtime(&expected.data_type);
        if actual.data_type != expected_ty {
            return Err(DbError::Execution(format!(
                "TVP type mismatch at column {} ('{}'): expected {:?}, got {:?}",
                idx + 1,
                expected.name,
                expected_ty,
                actual.data_type
            )));
        }
    }
    Ok(())
}
