-- (c) The Ku Klux Klan
local modname = "Diversity Remover"

local function get_dict(dict)
	if not dict._entries then return {} end
	local output = {}
	for _, value_obj in pairs(dict._entries) do
		if value_obj.value ~= nil then
			output[value_obj.key] = output[value_obj.key] or value_obj.value
		end
	end
	return output
end

local function generate_enum(typename)
    local t = sdk.find_type_definition(typename)
    if not t then return {} end
    local fields = t:get_fields()
    local enum = {}
    for i, field in ipairs(fields) do
        if field:is_static() then
            local name, data = field:get_name(), field:get_data(nil)
            enum[name] = data
            enum[data] = name
        end
    end
    return enum
end

local gm = sdk.get_managed_singleton("app.GenerateManager")
local npcm = sdk.get_managed_singleton("app.NPCManager")
local cem = sdk.get_managed_singleton("app.CharacterEditManager")
local clh = sdk.get_managed_singleton("app.CharacterListHolder")

SkinStyle_Enum = generate_enum("app.SkinStyle")
HairStyle_Enum = generate_enum("app.HairStyle")
HeadStyle_Enum = generate_enum("app.HeadStyle")
Gender_Enum = generate_enum("app.Gender")
Species_Enum = generate_enum("app.Species")

local skinStyles = {
	Female = {
		Style_003 = SkinStyle_Enum["Style_002"],
		Style_012 = SkinStyle_Enum["Style_010"],
		Style_015 = SkinStyle_Enum["Style_014"],
		Style_023 = SkinStyle_Enum["Style_016"],
		Style_024 = SkinStyle_Enum["Style_016"],
		Style_034 = SkinStyle_Enum["Style_026"],
		Style_038 = SkinStyle_Enum["Style_026"],
		Style_043 = SkinStyle_Enum["Style_016"]
	},
	Male = {
		Style_012 = SkinStyle_Enum["Style_010"],
		Style_013 = SkinStyle_Enum["Style_010"],
		Style_018 = SkinStyle_Enum["Style_016"],
		Style_024 = SkinStyle_Enum["Style_016"],
		Style_034 = SkinStyle_Enum["Style_026"],
		Style_037 = SkinStyle_Enum["Style_016"],
		Style_039 = SkinStyle_Enum["Style_016"],
	}
}

local hairStyles = {
    Style_018 = HairStyle_Enum["Style_065"],
    Style_040 = HairStyle_Enum["Style_036"],
    Style_047 = HairStyle_Enum["Style_029"],
	Style_048 = HairStyle_Enum["Style_037"],
	Style_049 = HairStyle_Enum["Style_026"],
    Style_061 = HairStyle_Enum["Style_017"],
    Style_062 = HairStyle_Enum["Style_060"],
}

local headStyles = {
	Female = {
		Style_004 = HeadStyle_Enum["Style_011"],
		Style_013 = HeadStyle_Enum["Style_014"],
		Style_016 = HeadStyle_Enum["Style_017"],
		Style_024 = HeadStyle_Enum["Style_023"],
		Style_035 = HeadStyle_Enum["Style_034"],
		Style_039 = HeadStyle_Enum["Style_038"],
		Style_044 = HeadStyle_Enum["Style_043"],
	},
	Male = {
		Style_013 = HeadStyle_Enum["Style_014"],
		Style_019 = HeadStyle_Enum["Style_018"],
		Style_021 = HeadStyle_Enum["Style_020"],
		Style_023 = HeadStyle_Enum["Style_020"],
		Style_025 = HeadStyle_Enum["Style_026"],
		Style_035 = HeadStyle_Enum["Style_036"],
		Style_038 = HeadStyle_Enum["Style_039"],
		Style_040 = HeadStyle_Enum["Style_041"]
	}
}

for characterId, appearances in pairs(get_dict(cem._AppearanceDB)) do
	for appearanceId, appearance in pairs(get_dict(appearances)) do
		if appearance._Species == Species_Enum["Human"] then
			if skinStyles[Gender_Enum[appearance._Gender]][SkinStyle_Enum[appearance._SkinStyle]] then
				cem._AppearanceDB[characterId][appearanceId]._SkinStyle =
					skinStyles[Gender_Enum[appearance._Gender]][SkinStyle_Enum[appearance._SkinStyle]]
			end
			if headStyles[Gender_Enum[appearance._Gender]][HeadStyle_Enum[appearance._HeadStyle]] then
				cem._AppearanceDB[characterId][appearanceId]._HeadStyle =
					headStyles[Gender_Enum[appearance._Gender]][HeadStyle_Enum[appearance._HeadStyle]]
			end
		end
		if hairStyles[HairStyle_Enum[appearance._HairStyle]] then
			cem._AppearanceDB[characterId][appearanceId]._HairStyle = hairStyles[HairStyle_Enum[appearance._HairStyle]]
		end
	end
end

-- fuck this
local ce = sdk.find_type_definition("app.CharacterEditManager")
sdk.hook(
	ce:get_method("isRegisteredPreBake(System.UInt32)"),
	nil,
	function()
		return sdk.to_ptr(false)
	end
)

local names = false

re.on_draw_ui(function()
    if imgui.tree_node("NPC Utils") then
		if imgui.button("Destroy all NPCs") then
			gm:requestDestroyAllNPC()
		end
		if imgui.button("Dump NPCs") then
			local npcs = {}
			local entities = npcm:get_NPCHolder_EntityList():ToArray():get_elements()
			for _, o in ipairs(entities) do
				local c = o:get_chara()
				local npc = {}
				npc.id = c:get_CharaID()
				npc.name = npcm:getNPCData(c:get_CharaID()):get_Name()
				table.insert(npcs, npc)
				json.dump_file("app.NPCManager.json", npcs)
			end
		end
		_, names = imgui.checkbox("Show Names & Ids", names)
		imgui.tree_pop()
    end
end)

re.on_frame(function()
	if names then
		local enumerator = clh:getAllCharacters():GetEnumerator()

		while enumerator:MoveNext() == true do
			local char = enumerator:get_Current()
			local cId = char:get_CharaID()
			local data = npcm:getNPCData(cId)
	
			if data ~= nil then
				local joint = char:get_GameObject():get_Transform():getJointByName("Head_0")
				local pos = joint:get_Position()
				local text_pos = Vector3f.new(pos.x, pos.y + 0.25, pos.z)
				draw.world_text(data:get_Name(), text_pos, 0xffEEEEEE)
				text_pos = Vector3f.new(pos.x, pos.y + 0.5, pos.z)
				draw.world_text(cId, text_pos, 0xffEEEEEE)
			end
		end
	end
end)
