local utils = require("utils")
local tblUtil = utils.table
local dialogs = require("dialogs")
local class = require("class")
local md = require("debugFunctions")
local async_util = require("async_util")
local topics = require("ui_topics")

local InventoryController = class()
local selectedData = nil

ScpuiSystem.modelDraw = nil


--backstock.default is global and set in backstock-sct
--backstock.current is global and set in backstock-sct

function InventoryController:init()

	self.first_run = false

	--Translatable strings
	self.strings = {
		Remaining = {"Remaining", -1},
		FactionIntro = {"Typically flown by the", -1},
		Type = {"Ship Type", -1},
		Maneuver = {"Maneuverability Rating", -1},
		Armor = {"Armor Rating", -1},
		Manufacturer = {"Manufactured by", -1},
		Afterburn = {"Max Afterburner Fuel", -1},
		Countermeasures = {"Countermeasure Capacity", -1},
		Power = {"Power Generator Capacity", -1},
		PowerSuffix = {"mw", -1},
		CreatedByIntro = {"Designed and Manufactured by", -1},
		Seeking = {"Weapon Type", -1},
		Range = {"Range", -1},
		Speed = {"Speed", -1},
		Damage = {"Damage Yield", -1},
		DPS = {"Damage Per Second", -1},
		ArmorFactor = {"Armor Damage", -1},
		ShieldFactor = {"Shield Damage", -1},
		SubsystemFactor = {"Subsystem Damage", -1},
		CargoSize = {"Bank Capacity Used Per Unit", -1},
		SpeedSuffix = {"m/s", -1},
		DamageSuffix = {"KEb", -1},
		DPSSuffix = {"KEb/s", -1},
		RangeSuffix = {"m", -1},
		NoData = {"No Data Loaded", -1}
	}

end

--Load default and current backstock values if available
function InventoryController:LoadData()

	backstock:LoadDataQuick()

end

function InventoryController:initialize(document)

    self.document = document

	---Load background choice
	self.document:GetElementById("main_background"):SetClass(ScpuiSystem:getBackgroundClass(), true)
	
	--For BtA: Set the class custom. This is a thing because Journal needs to be modular to SCPUI as well as BtA.
	--So eventually this will need a separate file to add it's own hooks into ui_topics that can then be referenced.
	--But for now we just brute force it.
	self.document:GetElementById("main_background"):SetClass("inventory_bg", true)
	
	---Load the desired font size from the save file
	self.document:GetElementById("main_background"):SetClass(("base_font" .. ScpuiSystem:getFontPixelSize()), true)
	self.document:GetElementById("inventory_title"):SetClass("h2", true)
	self.document:GetElementById("inventory_count"):SetClass("h1", true)
	self.document:GetElementById("req_text"):SetClass("h1", true)

	--Always reload data to reflect the latest changes
	self:LoadData()

    self:registerEventHandlers()
	
	local player = ba.getCurrentPlayer()
	local campaignfilename = player:getCampaignFilename()

	--If Requisitions is empty then hide the button completely
	local reqsAvail = #backstock.current.requisitions.ships + #backstock.current.requisitions.primaries + #backstock.current.requisitions.secondaries
	md.print("INVENTORY detected num requisitions at " .. reqsAvail)
	if reqsAvail == 0 then
		md.print("INVENTORY is hiding the Requisitions button!")
		self.document:GetElementById("top_panel_a"):SetClass("hidden", true)
	end

	self.SelectedEntry = nil
	
	self.SelectedSection = nil
	
	if ScpuiSystem.InventorySection == nil then
		ScpuiSystem.InventorySection = 1
	end
	
	self:ChangeSection(ScpuiSystem.InventorySection)
	
end

function InventoryController:ChangeSection(section)

	if section ~= self.SelectedSection then
		
		ScpuiSystem.InventorySection = section
	
		local itemList = nil
		local saveList = nil
	
		if section == 1 then
			itemList = backstock.default.ships
			saveList = backstock.current.ships
			selectedData = "ships"
		elseif section == 2 then
			itemList = backstock.default.primaries
			saveList = backstock.current.primaries
			selectedData = "primaries"
		elseif section == 3 then
			itemList = backstock.default.secondaries
			saveList = backstock.current.secondaries
			selectedData = "secondaries"
		end
		
		md.print("INVENTORY setting selected data type to " .. selectedData)

		if self.SelectedEntry then
			self:ClearEntry()
		end

		--If we had an old section on, remove the active class
		if self.SelectedSection then
			local oldbullet = self.document:GetElementById("btn_"..self.SelectedSection)
			oldbullet:SetPseudoClass("checked", false)
		end

		self.SelectedSection = section
		
		--Only create entries if there are any to create
		if itemList[1] then
			self:CreateEntries(itemList)
			--It's possible for the top entry in the index to be locked. In that case, auto select the next one instead.
			for i, v in ipairs(saveList) do
				if saveList[i].unlocked and saveList[i].remaining > 0 then
					self:SelectEntry(itemList[i].name, i)
					break
				end
			end
		else
			local list_el = self.document:GetElementById("list_items_ul")
			ScpuiSystem:ClearEntries(list_el)
			self:ClearData()
		end
		
		local newbullet = self.document:GetElementById("btn_"..self.SelectedSection)
		newbullet:SetPseudoClass("checked", true)


	end
	
end

function InventoryController:CreateEntryItem(entry, index)

	local li_el = self.document:CreateElement("li")
	
	local displayName = entry

	--For weapons let's use the tech title for the list instead
	if selectedData ~= "ships" then
		displayName = tb.WeaponClasses[entry].Title
	end
	
	--Find default item data
	local defaultIndex = utils.getTableIndex(backstock.default[selectedData], entry)
	local defaultData = backstock.default[selectedData][defaultIndex]
	
	--Find save item data
	local saveIndex = utils.getTableIndex(backstock.current[selectedData], entry)
	local saveData = backstock.current[selectedData][saveIndex]
	
	local amountRemaining = saveData.remaining or defaultData.default

	li_el.inner_rml = "<span class=\"inventorylist_left\">" .. displayName .. "</span><span class=\"inventorylist_right\">" .. amountRemaining .. "</span>"
	li_el.id = entry

	li_el:SetClass("inventorylist_element", true)
	li_el:SetClass("button_1", true)
	li_el:AddEventListener("click", function(_, _, _)
		self:SelectEntry(defaultData.key)
	end)
	
	defaultData.key = li_el.id

	return li_el
end

function InventoryController:CreateEntries(section)

	local list_el = self.document:GetElementById("list_items_ul")

	ScpuiSystem:ClearEntries(list_el)

	for i, v in ipairs(section) do
		--Find save item data
		local saveIndex = utils.getTableIndex(backstock.current[selectedData], v.name)
		local saveData = backstock.current[selectedData][saveIndex]

		if saveData.unlocked and saveData.remaining > 0 then
			md.print("INVENTORY Adding entry " .. i .. ": " .. v.name)
			list_el:AppendChild(self:CreateEntryItem(v.name, i))
		end
	end
end

function InventoryController:ClearEntry()

	self.document:GetElementById(self.SelectedEntry):SetPseudoClass("checked", false)
	self.SelectedEntry = nil

end

function InventoryController:ClearData()

	ScpuiSystem.modelDraw = nil
	self.document:GetElementById("inventory_title").inner_rml = "<p>" .. utils.xstr(self.strings.NoData) .. "</p>"
	self.document:GetElementById("inventory_count").inner_rml = "<p></p>"
	self.document:GetElementById("inventory_desc").inner_rml = "<p></p>"
	
end

function InventoryController:SelectEntry(key)

	--Find default item data
	local defaultIndex = utils.getTableIndex(backstock.default[selectedData], key)
	local defaultData = backstock.default[selectedData][defaultIndex]
	md.print("INVENTORY found " .. key .. " in default table " .. selectedData .. " at index " .. defaultIndex)
	
	--Find save item data
	local saveIndex = utils.getTableIndex(backstock.current[selectedData], key)
	local saveData = backstock.current[selectedData][saveIndex]
	md.print("INVENTORY found " .. key .. " in save table " .. selectedData .. " at index " .. saveIndex)


	if key ~= self.SelectedEntry then
	
		ScpuiSystem.modelDraw = {}
		ScpuiSystem.modelRot = 40
	
		if self.SelectedEntry then
			local oldEntry = self.document:GetElementById(self.SelectedEntry)
			if oldEntry then oldEntry:SetPseudoClass("checked", false) end
		end
		
		md.print("INVENTORY getting id for " .. key)
		local thisEntry = self.document:GetElementById(key)
		self.SelectedEntry = key
		thisEntry:SetPseudoClass("checked", true)
		
		local amountRemaining = saveData.remaining or defaultData.default

		self.document:GetElementById("inventory_title").inner_rml = "<p>" .. defaultData.name .. "</p>"
		self.document:GetElementById("inventory_count").inner_rml = "<p>" .. utils.xstr(self.strings.Remaining).. ": " .. amountRemaining .. "</p>"
		
		--Decide if item is a weapon or a ship
		if selectedData == "ships" then
			local thisShipClass = tb.ShipClasses[key]
			
			if self.first_run == false then
				async.run(function()
					async.await(async_util.wait_for(0.001))
					ScpuiSystem.modelDraw.class = key
					ScpuiSystem.modelDraw.element = self.document:GetElementById("inventory_view")
					self.first_run = true
				end, async.OnFrameExecutor)
			else
				ScpuiSystem.modelDraw.class = key
				ScpuiSystem.modelDraw.element = self.document:GetElementById("inventory_view")
			end
			
			
			--Let's convert PowerOutput to something interesting
			local power = math.ceil(thisShipClass.PowerOutput * 10) * 100
			local thisShipPower = power .. utils.xstr(self.strings.PowerSuffix)
			local thisShipTechDesc = topics.ships.description:send(thisShipClass)
			
			--This is the big call that writes all the things. I don't know a better way of doing this while maintaining maximum utility to translate and keep the rml clean.
			self.document:GetElementById("inventory_desc").inner_rml = "<p>" .. thisShipClass.Description .. "<br></br><br></br>" .. utils.xstr(self.strings.FactionIntro) .. " " .. defaultData.faction .. ".<br></br><br></br>" .. utils.xstr(self.strings.Type) .. ": <span class=\"white\">" .. thisShipClass.TypeString .. "</span><br></br>" .. utils.xstr(self.strings.Maneuver) .. ": <span class=\"white\">" .. thisShipClass.ManeuverabilityString .. "</span><br></br>" .. utils.xstr(self.strings.Armor) .. ": <span class=\"white\">" .. thisShipClass.ArmorString .. "</span><br></br>" .. utils.xstr(self.strings.Manufacturer) .. ": <span class=\"white\">" .. thisShipClass.ManufacturerString .. "</span><br></br>" .. utils.xstr(self.strings.Afterburn) .. ": <span class=\"white\">" .. thisShipClass.AfterburnerFuelMax .. "</span><br></br>" .. utils.xstr(self.strings.Countermeasures) .. ": <span class=\"white\">" .. thisShipClass.CountermeasuresMax .. "</span><br></br>" .. utils.xstr(self.strings.Power) .. ": <span class=\"white\">" .. thisShipPower .. "</span><br></br><br></br><div class=\"hr\"></div>" .. thisShipTechDesc .."</p>"

		else
			local thisWeaponClass = tb.WeaponClasses[key]
			
			if self.first_run == false then
				async.run(function()
					async.await(async_util.wait_for(0.001))
					ScpuiSystem.modelDraw.class = key
					ScpuiSystem.modelDraw.element = self.document:GetElementById("inventory_view")
					self.first_run = true
				end, async.OnFrameExecutor)
			else
				ScpuiSystem.modelDraw.class = key
				ScpuiSystem.modelDraw.element = self.document:GetElementById("inventory_view")
			end
			
			--For weapons lets use the Tech Title instead
			self.document:GetElementById("inventory_title").inner_rml = "<p>" .. thisWeaponClass.Title .. "</p>"
			
			--Handle custom data
			local stats = topics.weapons.stats:send(thisWeaponClass)
			local thisWeaponCreated = defaultData.creator
			local thisWeaponType = defaultData.category
			local thisWeaponRange = math.floor(stats.Range) .. " " .. utils.xstr(self.strings.RangeSuffix)
			local thisWeaponSpeed = stats.Velocity .. " " .. utils.xstr(self.strings.SpeedSuffix)
			local thisWeaponArmor = math.floor(stats.HullDamage / thisWeaponClass.FireWait) .. " " .. utils.xstr(self.strings.DPSSuffix)
			local thisWeaponShield = math.floor(stats.ShieldDamage / thisWeaponClass.FireWait) .. " " .. utils.xstr(self.strings.DPSSuffix)
			local thisWeaponSubsystem = math.floor(stats.SubsystemDamage / thisWeaponClass.FireWait) .. " " .. utils.xstr(self.strings.DPSSuffix)
			local thisWeaponCargoSize = "" --Only display this for secondaries
			local thisWeaponTechDesc = topics.weapons.description:send(thisWeaponClass)
			
			--Handle data only for Secondaries
			if selectedData == "secondaries" then
				thisWeaponCargoSize = utils.xstr(self.strings.CargoSize) .. ": <span class=\"white\">" .. thisWeaponClass.CargoSize .. "</span>"
			end
			
			--This is the big call that writes all the things. I don't know a better way of doing this while maintaining maximum utility to translate and keep the rml clean.
			self.document:GetElementById("inventory_desc").inner_rml = "<p>" .. thisWeaponClass.Title .. "<br></br><br></br>" .. utils.xstr(self.strings.CreatedByIntro) .. " " .. thisWeaponCreated .. ".<br></br><br></br>" .. utils.xstr(self.strings.Seeking) .. ": <span class=\"white\">" .. thisWeaponType .. "</span><br></br>" .. utils.xstr(self.strings.Range) .. ": <span class=\"white\">" .. thisWeaponRange .. "</span><br></br>" .. utils.xstr(self.strings.Speed) .. ": <span class=\"white\">" .. thisWeaponSpeed .. "</span><br></br>" .. utils.xstr(self.strings.ArmorFactor) .. ": <span class=\"white\">" .. thisWeaponArmor .. "</span><br></br>" .. utils.xstr(self.strings.ShieldFactor) .. ": <span class=\"white\">" .. thisWeaponShield .. "</span><br></br>" .. utils.xstr(self.strings.SubsystemFactor) .. ": <span class=\"white\">" .. thisWeaponSubsystem .. "</span><br></br>" .. thisWeaponCargoSize .. "<br></br><div class=\"hr\"></div>" .. thisWeaponTechDesc .."</p>"
		end

	end	


end

function InventoryController:DrawModel()

	if ScpuiSystem.modelDraw and ScpuiSystem.substate == "Inventory" then  --Haaaaaaacks
		local thisObjectClass = nil
		
		if ScpuiSystem.modelDraw.class == nil then return end
		
		if selectedData == "ships" then
			thisObjectClass = tb.ShipClasses[ScpuiSystem.modelDraw.class]
		else
			thisObjectClass = tb.WeaponClasses[ScpuiSystem.modelDraw.class]
		end
		
		ScpuiSystem.modelRot = ScpuiSystem.modelRot + (7 * ba.getRealFrametime())

		if ScpuiSystem.modelRot >= 100 then
			ScpuiSystem.modelRot = ScpuiSystem.modelRot - 100
		end
		
		local modelView = ScpuiSystem.modelDraw.element
						
		local modelLeft = modelView.offset_left + modelView.parent_node.offset_left + modelView.parent_node.parent_node.offset_left + 25 --This is pretty messy, but it's functional
		local modelTop = modelView.parent_node.offset_top + modelView.parent_node.parent_node.offset_top - 7 --Does not include modelView.offset_top because that element's padding is set for anims also subtracts 7px for funsies
		local modelWidth = modelView.offset_width
		local modelHeight = modelView.offset_height
		
		thisObjectClass:renderTechModel(modelLeft, modelTop, modelLeft + modelWidth, modelTop + modelHeight, ScpuiSystem.modelRot, -15, 0, 1.1)
	end

end

function InventoryController:Quit()
    ba.postGameEvent(ba.GameEvents["GS_EVENT_MAIN_MENU"])
    self.document:Close()
end

function InventoryController:Exit(element)

    ui.playElementSound(element, "click", "success")
	self:Quit()
end

function InventoryController:Requisitions(element)

    ui.playElementSound(element, "click", "success")
	ScpuiSystem:beginSubstate("Requisitions")
	self.document:Close()

end

function InventoryController:registerEventHandlers()

end

function InventoryController:global_keydown(_, event)
    if event.parameters.key_identifier == rocket.key_identifier.ESCAPE then
        event:StopPropagation()
		self:Quit()
    end
end

function InventoryController:unload()
    ScpuiSystem:freeAllModels()
end

engine.addHook("On Frame", function()
	if ScpuiSystem.render == true then
		InventoryController:DrawModel()
	end
end, {}, function()
	return false
end)

return InventoryController
