// Used in the GasaGen.cpp translation unit
#if GASA_INTELLISENSE_DIRECTIVES
#pragma once
#define GEN_EXPOSE_BACKEND
#include "gen.hpp"
#include "gen.builder.hpp"
#include "GasaGenCommon.cpp"
using namespace gen;
#endif

void gen_FGasaDevOptionsCache()
{
	Array<CodeVar> GasaDevOptions_UPROPERTIES = Array<CodeVar>::init(GlobalAllocator);
	{
		CodeBody  header_GasaDevOptions = parse_file( path_module_gasa "GasaDevOptions.h" );
		CodeClass UGasaDevOptions = NoCode;
		for (Code entry : header_GasaDevOptions)
		{
			if ( entry->Type == ECode::Class && entry->Name.starts_with( txt("UGasaDevOptions")) )
			{
				UGasaDevOptions = entry.cast<CodeClass>();
				break;
			}
		}
		for (Code member = UGasaDevOptions->Body.begin(); member != UGasaDevOptions->Body.end(); ++ member)
		{
			if ( member->Type == ECode::Untyped && member->Name.starts_with(str_UPROPERTY) )
				++ member;
			if ( member->Type == ECode::Variable
			&& (	member->ValueType->Name.starts_with( txt("TSoftClassPtr"))
				||  member->ValueType->Name.starts_with( txt("TSoftObjectPtr")) )
			)
				GasaDevOptions_UPROPERTIES.append(member.cast<CodeVar>());
		}
	}

	CodeComment generation_notice = def_comment(txt("Generated by GasaGen/GasaGen_DevOptionsCache.cpp"));

	Builder header = Builder::open( path_module_gasa "GasaDevOptionsCache.h" );
	{
		header.print( generation_notice );
		header.print( pragma_once );
		header.print( fmt_newline );
		header.print( def_include(txt("GasaDevOptionsCache.generated.h")));
		header.print( fmt_newline );

		header.print( UHT_USTRUCT );
		CodeStruct FGasaDevOptionsCache;
		{
			CodeBody body = def_body(ECode::Struct_Body);
			{
				CodeType t_UClassPtr  = parse_type(code(UClass*));
				CodeType t_UObjectPtr = parse_type(code(UObject*));

				body.append(UHT_GENERATED_BODY);
				body.append(fmt_newline);
				for (CodeVar var : GasaDevOptions_UPROPERTIES)
				{
					if ( var->ValueType->Name.starts_with( txt("TSoftClassPtr") )) {
						body.append(UHT_UPROPERTY);
						body.append( def_variable(t_UClassPtr, var->Name));
					}
					if ( var->ValueType->Name.starts_with( txt("TSoftObjectPtr") )) {
						body.append(UHT_UPROPERTY);
						body.append( def_variable(t_UObjectPtr, var->Name));
					}
				}
				body.append(fmt_newline);
				body.append( parse_function(code( void CachedDevOptions(); )));
			}
			FGasaDevOptionsCache = parse_struct( token_fmt( "body", (StrC)body.to_string(), stringize(
				struct GASA_API FGasaDevOptionsCache {
					<body>
				};
			)));
		}
		header.print(FGasaDevOptionsCache);
		header.print( fmt_newline );
		header.write();
		format_file( path_module_gasa "GasaDevOptionsCache.h" );
	}

	Builder source = Builder::open( path_module_gasa "GasaDevOptionsCache.cpp" );
	{
		Array<CodeInclude> GasaDevOptions_Includes  = Array<CodeInclude>::init(GlobalAllocator);
		{
			CodeBody source_GasaDevOptions = parse_file( path_module_gasa "GasaDevOptions.cpp");
			for ( Code entry : source_GasaDevOptions )
			{
				if ( entry->Type == ECode::Preprocess_Include )
					GasaDevOptions_Includes.append( entry.cast<CodeInclude>() );
			}
		}

		source.print( generation_notice );
		source.print( def_include(txt("GasaDevOptionsCache.h")));
		source.print(fmt_newline);
		for ( CodeInclude include : GasaDevOptions_Includes ) {
			source.print( include );
		}
		source.print( parse_using(code( using namespace Gasa; )));
		source.print(fmt_newline);

		CodeBody cached_property_assignments = def_body(ECode::Function_Body);
		{
			cached_property_assignments.append(fmt_newline);
			cached_property_assignments.append(fmt_newline);
			for (CodeVar var : GasaDevOptions_UPROPERTIES)
			{
				#pragma push_macro("TEXT")
				#undef TEXT
				Code assignment = code_fmt( "property", (StrC)var->Name, stringize(
					<property> = DevOpts-> <property>.LoadSynchronous();
					ensureMsgf(<property> != nullptr, TEXT("<property> is null, DO NOT RUN PIE or else you may get a crash if not handled in BP or C++"));
				));
				#pragma pop_macro("TEXT")
				cached_property_assignments.append(assignment);
				cached_property_assignments.append(fmt_newline);
				cached_property_assignments.append(fmt_newline);
			}
		}

		CodeFn CachedDevOptions = parse_function( token_fmt(
			"cached_property_assignments", (StrC)cached_property_assignments.to_string(),
		stringize(
			void FGasaDevOptionsCache::CachedDevOptions()
			{
				UGasaDevOptions* DevOpts = GetMutDevOptions();

				<cached_property_assignments>

				Tag_GlobalPPV = DevOpts->Tag_GlobalPPV;
			})
		));
		source.print(CachedDevOptions);
		source.write();
		format_file( path_module_gasa "GasaDevOptionsCache.cpp" );
	}
}
