use crate::records::type_function_reduction_guesser::TypeFunctionReductionGuesser;
use crate::type_aliases::type_id::TypeId;

use crate::functions::follow_type::follow_type_id;
use crate::functions::follow_type_utils::follow_optional_ty;
use crate::records::type_function_instance_type::TypeFunctionInstanceType;

impl TypeFunctionReductionGuesser {
    pub fn guess_type(&mut self, arg: TypeId) -> Option<TypeId> {
        let t = unsafe { follow_type_id(arg) };

        if self.substitutable.contains(&t) {
            let subst_opt = self.substitutable.find(&t).copied();
            let subst = unsafe { follow_optional_ty(subst_opt) }.unwrap_or(subst_opt.unwrap());
            if subst == t || self.substitutable.contains(&subst) {
                return Some(subst);
            } else if unsafe {
                crate::functions::get_type_alt_j::get_type_id::<TypeFunctionInstanceType>(subst)
                    .is_null()
            } {
                return Some(subst);
            } else {
                return self.guess_type(subst);
            }
        }

        if !unsafe {
            crate::functions::get_type_alt_j::get_type_id::<TypeFunctionInstanceType>(t).is_null()
        } {
            if self.function_reduces_to.contains(&t) {
                return self.function_reduces_to.find(&t).copied();
            }
        }

        None
    }
}
