mod intersect_type;
mod remove_type;
mod test;
mod union_type;

use super::LuaType;
use crate::DbIndex;
pub(crate) use union_type::union_type_shallow;

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum TypeOps {
    /// Add a type to the source type
    Union,
    /// Intersect a type with the source type
    Intersect,
    /// Remove a type from the source type
    Remove,
}

impl TypeOps {
    pub fn apply(&self, db: &DbIndex, source: &LuaType, target: &LuaType) -> LuaType {
        match self {
            TypeOps::Union => union_type::union_type(db, source.clone(), target.clone()),
            TypeOps::Intersect => {
                intersect_type::intersect_type(db, source.clone(), target.clone())
            }
            TypeOps::Remove => {
                let result = remove_type::remove_type(db, source.clone(), target.clone());
                if let Some(result) = result {
                    return result;
                }

                match &source {
                    LuaType::Nil => LuaType::Never,
                    _ => source.clone(),
                }
            }
        }
    }

    pub fn union_all<I>(db: &DbIndex, types: I) -> LuaType
    where
        I: IntoIterator<Item = LuaType>,
    {
        union_type::union_type_all(db, types)
    }
}
