use crate::records::non_strict_context::NonStrictContext;
use crate::records::non_strict_type_checker::NonStrictTypeChecker;
use crate::records::stack_pusher_non_strict_type_checker::StackPusher;
use luaur_ast::records::ast_node::AstNode;
use luaur_ast::records::ast_stat::AstStat;
use luaur_ast::records::ast_stat_assign::AstStatAssign;
use luaur_ast::records::ast_stat_block::AstStatBlock;
use luaur_ast::records::ast_stat_break::AstStatBreak;
use luaur_ast::records::ast_stat_class::AstStatClass;
use luaur_ast::records::ast_stat_compound_assign::AstStatCompoundAssign;
use luaur_ast::records::ast_stat_continue::AstStatContinue;
use luaur_ast::records::ast_stat_declare_extern_type::AstStatDeclareExternType;
use luaur_ast::records::ast_stat_declare_function::AstStatDeclareFunction;
use luaur_ast::records::ast_stat_declare_global::AstStatDeclareGlobal;
use luaur_ast::records::ast_stat_error::AstStatError;
use luaur_ast::records::ast_stat_expr::AstStatExpr;
use luaur_ast::records::ast_stat_for::AstStatFor;
use luaur_ast::records::ast_stat_for_in::AstStatForIn;
use luaur_ast::records::ast_stat_function::AstStatFunction;
use luaur_ast::records::ast_stat_if::AstStatIf;
use luaur_ast::records::ast_stat_local::AstStatLocal;
use luaur_ast::records::ast_stat_local_function::AstStatLocalFunction;
use luaur_ast::records::ast_stat_repeat::AstStatRepeat;
use luaur_ast::records::ast_stat_return::AstStatReturn;
use luaur_ast::records::ast_stat_type_alias::AstStatTypeAlias;
use luaur_ast::records::ast_stat_type_function::AstStatTypeFunction;
use luaur_ast::records::ast_stat_while::AstStatWhile;
use luaur_common::LUAU_ASSERT;

impl NonStrictTypeChecker {
    pub fn visit_ast_stat(&mut self, stat: *mut AstStat) -> NonStrictContext {
        unsafe {
            let _pusher = self.push_stack(stat as *mut AstNode);
            let node = stat as *mut AstNode;
            if (*node).is::<AstStatBlock>() {
                self.visit_ast_stat_block(stat as *mut AstStatBlock)
            } else if (*node).is::<AstStatIf>() {
                self.visit_ast_stat_if(stat as *mut AstStatIf)
            } else if (*node).is::<AstStatWhile>() {
                self.visit_ast_stat_while(stat as *mut AstStatWhile)
            } else if (*node).is::<AstStatRepeat>() {
                self.visit_ast_stat_repeat(stat as *mut AstStatRepeat)
            } else if (*node).is::<AstStatBreak>() {
                self.visit_ast_stat_break(stat as *mut AstStatBreak);
                NonStrictContext::non_strict_context()
            } else if (*node).is::<AstStatContinue>() {
                self.visit_ast_stat_continue(stat as *mut AstStatContinue);
                NonStrictContext::non_strict_context()
            } else if (*node).is::<AstStatReturn>() {
                self.visit_ast_stat_return(stat as *mut AstStatReturn)
            } else if (*node).is::<AstStatExpr>() {
                self.visit_ast_stat_expr(stat as *mut AstStatExpr)
            } else if (*node).is::<AstStatLocal>() {
                self.visit_ast_stat_local(stat as *mut AstStatLocal)
            } else if (*node).is::<AstStatFor>() {
                self.visit_ast_stat_for(stat as *mut AstStatFor)
            } else if (*node).is::<AstStatForIn>() {
                self.visit_ast_stat_for_in(stat as *mut AstStatForIn)
            } else if (*node).is::<AstStatAssign>() {
                self.visit_ast_stat_assign(stat as *mut AstStatAssign)
            } else if (*node).is::<AstStatCompoundAssign>() {
                self.visit_ast_stat_compound_assign(stat as *mut AstStatCompoundAssign)
            } else if (*node).is::<AstStatFunction>() {
                self.visit_ast_stat_function(stat as *mut AstStatFunction)
            } else if (*node).is::<AstStatLocalFunction>() {
                self.visit_ast_stat_local_function(stat as *mut AstStatLocalFunction)
            } else if (*node).is::<AstStatTypeAlias>() {
                self.visit_ast_stat_type_alias(stat as *mut AstStatTypeAlias)
            } else if (*node).is::<AstStatTypeFunction>() {
                self.visit_ast_stat_type_function(stat as *mut AstStatTypeFunction);
                NonStrictContext::non_strict_context()
            } else if (*node).is::<AstStatDeclareFunction>() {
                self.visit_ast_stat_declare_function(stat as *mut AstStatDeclareFunction)
            } else if (*node).is::<AstStatDeclareGlobal>() {
                self.visit_ast_stat_declare_global(stat as *mut AstStatDeclareGlobal)
            } else if (*node).is::<AstStatDeclareExternType>() {
                self.visit_ast_stat_declare_extern_type(stat as *mut AstStatDeclareExternType)
            } else if (*node).is::<AstStatClass>() {
                self.visit_ast_stat_class(stat as *mut AstStatClass)
            } else if (*node).is::<AstStatError>() {
                self.visit_ast_stat_error(stat as *mut AstStatError)
            } else {
                LUAU_ASSERT!(
                    false,
                    "NonStrictTypeChecker encountered an unknown statement type"
                );
                (*self.ice)
                    .ice_string("NonStrictTypeChecker encountered an unknown statement type");
                NonStrictContext::non_strict_context()
            }
        }
    }
}
