extends SceneTree

const WOW_M2_MATERIAL := preload("res://addons/mpq_extractor/loaders/wow_m2_material.gd")
const WOW_WMO_MATERIAL := preload("res://addons/mpq_extractor/loaders/wow_wmo_material.gd")

var _failures := 0


func _initialize() -> void:
	_check_project_descriptor_setting()
	_check_wmo_window_material()
	_check_wmo_wall_material()
	_check_wmo_glass_material()
	_check_m2_alpha_material()
	_check_m2_billboard_and_uv_rotation_shader()

	if _failures > 0:
		push_error("Renderer material verification failed: %d issue(s)" % _failures)
		quit(1)
		return

	print("Renderer material verification passed.")
	quit(0)


func _check_project_descriptor_setting() -> void:
	var descriptors := int(ProjectSettings.get_setting(
		"rendering/rendering_device/d3d12/max_resource_descriptors",
		0
	))
	_expect(
		descriptors >= 1048576,
		"D3D12 resource descriptor heap setting should be at least 1048576, got %d" % descriptors
	)


func _check_wmo_window_material() -> void:
	var mat := WOW_WMO_MATERIAL.build(
		null,
		null,
		0x11,
		0,
		0,
		"DUNGEONS/TEXTURES/WINDOWS/MM_ELWYNN_WND_EXT__01.BLP"
	)
	var code := mat.shader.code
	_expect(bool(mat.get_meta("wow_wmo_window_material", false)), "Elwynn exterior window should be tagged as a WMO window material")
	_expect(not bool(mat.get_meta("wow_wmo_glass_blend_material", false)), "Opaque Elwynn exterior window should not be tagged as glass blend")
	_expect(float(mat.get_shader_parameter("unlit_material")) > 0.5, "WMO flag 0x01 should make Elwynn exterior window unlit")
	_expect(code.contains("cull_back"), "Opaque WMO window atlas shader should use cull_back")
	_expect(not code.contains("cull_disabled"), "Opaque WMO window atlas shader should not use cull_disabled")
	_expect(code.contains("depth_draw_opaque"), "Opaque WMO window atlas shader should use opaque depth draw")
	_expect(code.contains("filter_linear, repeat_disable"), "WMO window atlas shader should use stable non-mipmapped albedo sampler")
	_expect(not code.contains("ALPHA ="), "Opaque WMO window atlas shader should not write ALPHA")


func _check_wmo_wall_material() -> void:
	var mat := WOW_WMO_MATERIAL.build(
		null,
		null,
		0,
		0,
		0,
		"DUNGEONS/TEXTURES/WALLS/MM_STRMWND_WALL_03.BLP"
	)
	var code := mat.shader.code
	_expect(not bool(mat.get_meta("wow_wmo_window_material", false)), "Stormwind wall texture name must not be matched as a window")
	_expect(float(mat.get_shader_parameter("unlit_material")) < 0.5, "Ordinary WMO wall should not be unlit")
	_expect(code.contains("cull_disabled"), "Ordinary WMO wall should keep cull_disabled")
	_expect(code.contains("filter_linear_mipmap_anisotropic, repeat_enable"), "Ordinary WMO wall should keep mipmapped repeating albedo sampler")


func _check_wmo_glass_material() -> void:
	var mat := WOW_WMO_MATERIAL.build(
		null,
		null,
		0,
		0,
		2,
		"DUNGEONS/TEXTURES/WINDOWS/MM_ELWYNN_WND_EXT__01.BLP"
	)
	var code := mat.shader.code
	_expect(bool(mat.get_meta("wow_wmo_glass_blend_material", false)), "BlendMode 2 WMO window should be tagged as glass")
	_expect(code.contains("cull_back"), "WMO glass shader should use cull_back")
	_expect(code.contains("depth_draw_never"), "WMO glass shader should avoid depth writes")
	_expect(code.contains("ALPHA = clamp"), "WMO glass shader should write alpha")


func _check_m2_alpha_material() -> void:
	var mat := WOW_M2_MATERIAL.build(
		null,
		null,
		null,
		null,
		0,
		2,
		0,
		0,
		0,
		0,
		"NewWaterfall",
		{}
	)
	var code := mat.shader.code
	_expect(code.contains("blend_mix"), "M2 alpha shader should use blend_mix")
	_expect(code.contains("depth_draw_never"), "M2 alpha shader should avoid depth writes")
	_expect(code.contains("ALPHA = clamp"), "M2 alpha shader should write alpha")


func _check_m2_billboard_and_uv_rotation_shader() -> void:
	var mat := WOW_M2_MATERIAL.build(
		null,
		null,
		null,
		null,
		0x04,
		0,
		0,
		0,
		0,
		0,
		"BillboardProbe",
		{
			"billboard_enabled": true,
			"stage0_uv_rotation": Vector4(0.0, -1.0, 1.0, 0.0),
			"stage0_uv_rotation_speed": 0.25,
		}
	)
	var code := mat.shader.code
	_expect(bool(mat.get_meta("wow_m2_billboard_enabled", false)), "M2 material should preserve billboard metadata")
	_expect(bool(mat.get_shader_parameter("billboard_enabled")), "M2 material should enable billboard shader parameter")
	_expect(code.contains("apply_m2_billboard"), "M2 shader should keep billboard vertex path")
	_expect(code.contains("CUSTOM0"), "M2 shader should consume CUSTOM0 billboard data")
	_expect(code.contains("stage0_uv_rotation"), "M2 shader should keep UV rotation uniforms")
	_expect(code.contains("uv_rotation_speed * TIME"), "M2 shader should keep animated UV rotation path")


func _expect(condition: bool, message: String) -> void:
	if condition:
		return
	_failures += 1
	push_error(message)
