require "ISUI/ISCollapsableWindow"
require "ISUI/ISTabPanel"
require "ISUI/ISTextEntryBox"
require "MultiSelectListbox"

local closingWindow = false
local MCGlobalAdvanceView = false
MCContainerDataPrefix = 'manageContainerData_'

ISConfigureContainerWindow = ISCollapsableWindow:derive("ISConfigureContainerWindow")
ISSimplePanel = ISPanelJoypad:derive("ISSimplePanel")

ISConfigureContainerWindow.windows = {}
ISConfigureContainerWindow.leftCategory = Keyboard.KEY_LEFT;
ISConfigureContainerWindow.rightCategory = Keyboard.KEY_RIGHT;
ISConfigureContainerWindow.upArrow = Keyboard.KEY_UP;
ISConfigureContainerWindow.downArrow = Keyboard.KEY_DOWN;
ISConfigureContainerWindow.FONT_HGT_SMALL = getTextManager():getFontHeight(UIFont.Small)

function ISConfigureContainerWindow:createChildren()
	ISCollapsableWindow.createChildren(self)
	local titleHeight = self:titleBarHeight()

	self:setInfo(getText("UI_ConfigureContainer"));

	self.infoButton = ISButton:new(self.closeButton:getRight() + 1, 15, 70, 1, getText("UI_InfoBtn"), self, self.onOptionMouseDown);
	self.collapseButton:setX(self:getWidth() - titleHeight - 3)
	self.pinButton:setX(self:getWidth()- titleHeight - 3)

	local inset = 4
	local fontRowHeight = self.FONT_HGT_SMALL
	local currentYMarker = 0

	-- Height will be set at the end
	self.simplePanel = ISSimplePanel:new(0, titleHeight, self.simpleViewWidth, 0)
	self.simplePanel:initialise()
	self:addChild(self.simplePanel)

	-- Simple View

	local lblNameText = getText("IGUI_Name") .. ":"
	local lblName = ISLabel:new(inset, 2, fontRowHeight, lblNameText, 1, 1, 1, 1.0, UIFont.Small, true)
	lblName:initialise();
	lblName:instantiate();
	self.simplePanel:addChild(lblName);

	local textboxNameX = getTextManager():MeasureStringX(UIFont.Small, lblNameText) + (inset * 2)
	self.textBoxName = ISTextEntryBox:new("", textboxNameX, 0, self.simpleViewWidth-textboxNameX, fontRowHeight)
	self.textBoxName:initialise()
	self.textBoxName:setAnchorRight(true)
	self.textBoxName:setAnchorTop(true)
	self.simplePanel:addChild(self.textBoxName)

	currentYMarker = currentYMarker + fontRowHeight + inset

	self.toggleAdvance = ISTickBox:new(inset, currentYMarker, 20, fontRowHeight, "", self, self.onToggleAdvance)
	self.toggleAdvance:initialise()
	self.toggleAdvance:addOption(getText("IGUI_Temp_AdvView"));
	self.toggleAdvance:setWidthToFit()
	self.simplePanel:addChild(self.toggleAdvance)

	currentYMarker = currentYMarker + fontRowHeight + (inset * 2)

	self.containerPresetDropdown = ISComboBox:new(inset, currentYMarker, self.simpleViewWidth - (inset * 2), fontRowHeight, self);
	self.containerPresetDropdown:setAnchorTop(true);
	self.containerPresetDropdown:setAnchorBottom(false);
	self.containerPresetDropdown.openUpwards = true;
	self.simplePanel:addChild(self.containerPresetDropdown)

	self.containerPresetDropdown.noSelectionText = getText("UI_characreation_SelectToLoad")
	self.containerPresetDropdown.selected = 0 -- no selection
	self:refreshPresets()

	currentYMarker = currentYMarker + fontRowHeight + inset

	self.applyPresetButton = ISButton:new(inset, currentYMarker, 50, fontRowHeight, getText("UI_btn_apply"), self, self.loadPreset);
	self.applyPresetButton:initialise();
	self.applyPresetButton:instantiate();
	self.applyPresetButton.borderColor = {r=0.7, g=0.7, b=0.7, a=0.5};
	self.simplePanel:addChild(self.applyPresetButton);

	self.savePresetButton = ISButton:new(self.applyPresetButton:getRight() + 10, currentYMarker, 50, fontRowHeight, getText("UI_btn_save"), self, self.showSavePopup);
	self.savePresetButton:initialise();
	self.savePresetButton:instantiate();
	self.savePresetButton.borderColor = {r=0.7, g=0.7, b=0.7, a=0.5};
	self.simplePanel:addChild(self.savePresetButton);

	self.deletePresetButton = ISButton:new(self.savePresetButton:getRight() + 10, currentYMarker, 50, fontRowHeight, getText("UI_btn_delete"), self, self.deletePresetConfirmation);
	self.deletePresetButton:initialise();
	self.deletePresetButton:instantiate();
	self.deletePresetButton.borderColor = {r=0.7, g=0.7, b=0.7, a=0.5};
	self.simplePanel:addChild(self.deletePresetButton);

	-- Add a button a row below that reads "Set categories using items in the container"
	currentYMarker = currentYMarker + fontRowHeight + inset

	self.applyContainerItemCatButton = ISButton:new(inset, currentYMarker, 50, fontRowHeight, getText("UI_SetCategoriesFromContainer"), self, self.onApplyContainerItemCat);
	self.applyContainerItemCatButton:initialise();
	self.applyContainerItemCatButton:instantiate();
	self.applyContainerItemCatButton.borderColor = {r=0.7, g=0.7, b=0.7, a=0.5};
	self.simplePanel:addChild(self.applyContainerItemCatButton);

	self.simplePanel:insertNewLineOfButtons(self.containerPresetDropdown, self.savePresetButton, self.deletePresetButton)
	self.simplePanel.joypadIndex = 1
	self.simplePanel.joypadIndexY = 1

	currentYMarker = currentYMarker + fontRowHeight + (self.applyContainerItemCatButton:getHeight() * 1.3)

	self.simplePanel:setHeight(currentYMarker + inset)

	self.panel = ISTabPanel:new(0, currentYMarker, self.simpleViewWidth, self:getHeight()-currentYMarker)
	self.panel:initialise()
	self.panel.target = self
	self.panel.onActivateView = self.onActivateView
	self.panel:setEqualTabWidth(false)
	self:addChild(self.panel)

	self.categoryListBox = MultiSelectListbox:new(0, self.panel.tabHeight, self.simpleViewWidth, self:getHeight()-(currentYMarker+self.panel.tabHeight), ISConfigureContainerWindow:fetchCategories(getAllItems()))
	self.categoryListBox:initialise();
  	self.categoryListBox:instantiate();
	--self.categoryListBox:setAnchorLeft(true)
	self.panel:addChild(self.categoryListBox)

	local categories = self.categoryListBox:GetListboxItems()
	for j=1,categories:size() do
		local category = categories:get(j-1)
		local categoryTransKey = "IGUI_ItemCat_" .. category
		local categoryTrans = getText(categoryTransKey)
		--If the translation did not pull, show key val
		categoryTrans = categoryTrans == categoryTransKey and category or categoryTrans
		self.categoryListBox:addItem(categoryTrans, category)
	end
	self.categoryListBox:sort()


	--Advance View
	self.advancePanel = ISPanel:new(self.simpleViewWidth, titleHeight, self.advanceViewWidth, self:getHeight())
	self.advancePanel:initialise();
	self:addChild(self.advancePanel);

	self:initList();

	--[[self.excludeRotten = ISTickBox:new(4, 2 + rowHeight + rowPadding + self.advPanel:getHeight(), 20, rowHeight, "", self, self.onToggleExcludeRotten)
	self.excludeRotten:initialise()
	self.excludeRotten:addOption(getText("IGUI_ExcludeRotten"));
	self.excludeRotten:setWidthToFit()
	self.advancePanel:addChild(self.excludeRotten)]]


	self:setObject(self.containers)

	self.panel:activateView(self:getContainerName(self.containers:get(0)))
end

function ISConfigureContainerWindow:addCategories(categories)
	self.categoryListBox:setSelectedByValues(categories)
end

function ISConfigureContainerWindow:addPanels(addNum)
	for i=0, addNum-1 do
		local dummyElem = ISUIElement:new(0, 0, 0, 0)
		local container = self.containers:get(self.containers:size() - addNum + i)
		self.panel:addView(self:getContainerName(container), dummyElem)
	end
end

function ISConfigureContainerWindow:removePanels(removeNum)
	--lets say I had 4  and now I have 1, I need to get index 1,2,3
	for i=0, removeNum-1 do
		local removeIndex = self.containers:size() - removeNum + i
		self.panel:removeView(self.panel:getView(self:getContainerName(self.containers:get(removeIndex))))
	end
end

function ISConfigureContainerWindow:setObject(newContainers)
	closingWindow = false
	self:saveChanges()
	self.prevContainerSelection = 0
	local diffContainers = newContainers:size() - self.prevContainersCount
	--reset view names
	for i,curView in ipairs(self.panel.viewList) do
		-- If we have 1 new container and there's more than 1 view,
		if (newContainers:size() < i) then
			break
		end
		curView.name = self:getContainerName(newContainers:get(i-1))
		local newWidth = getTextManager():MeasureStringX(UIFont.Small, curView.name) + self.panel.tabPadX
		curView.tabWidth = newWidth;
	end

	if (diffContainers > 0) then
		self.containers = newContainers
		self:addPanels(diffContainers)
	else
		self:removePanels(diffContainers*-1)
		self.containers = newContainers
	end
	self.panel:activateView(self:getContainerName(self.containers:get(self.containers:size()-1)))
	self.prevContainersCount = self.containers:size()
	self:refreshSelection()
	if JoypadState.players[self.playerNum+1] then
		setJoypadFocus(self.playerNum, self.categoryListBox)
	end
end

function ISConfigureContainerWindow:close()
	closingWindow = true
	self:saveChanges()
	getPlayer():setIgnoreAimingInput(false);
	self:removeFromUIManager()
	if JoypadState.players[self.playerNum+1] then
		setJoypadFocus(self.playerNum, nil)
	end
end

function ISConfigureContainerWindow:onToggleAdvance(index, selected)
	local newWidth = 0
	if selected then
		newWidth = self.simpleViewWidth+self.advanceViewWidth
	else
		newWidth = self.simpleViewWidth
	end
	self.advPanel:setVisible(selected)
	self:setWidth(newWidth)
end

function ISConfigureContainerWindow:onToggleRotten(index, selected)

end

--TODO: Find why this even does not trigger each time a view is clicked
function ISConfigureContainerWindow:onActivateView()
	self.onTabActivated(self, self.advPanel)

	if self.prevContainerSelection > 0 then
		self:saveChanges(self.prevContainerSelection)
	end
	self:refreshSelection()
	self.prevContainerSelection = self.panel:getActiveViewIndex()
end


ISConfigureContainerWindow.getContainerData = function(container, playerUUID, activeContainerIndex)
	local containerData = container:getModData()[MCContainerDataPrefix .. playerUUID] or {}
	-- Load default vals if not found in modData
	local defaultValues = {containerName="", containersFilters={}, exclusiveSelection={}--[[, excludeRotten=false]]}
	defaultValues.containersFilters[activeContainerIndex] = {}
	defaultValues.exclusiveSelection[activeContainerIndex] = {Include={}, Exclude={}} --default value sometimes not set
	for dataKey,dataValue in pairs(defaultValues) do
		if (containerData[dataKey] == nil) then
			containerData[dataKey] = dataValue
		end
	end
	return containerData
end

function ISConfigureContainerWindow:refreshSelection()
	self.onTabActivated(self, self.advPanel)
	
	local activeIndex = self.panel:getActiveViewIndex()
	local containerData = self.getContainerData(self.containers:get(0):getParent(), self.playerContainerID, activeIndex)

	self.textBoxName:setText(containerData.containerName)
	self.toggleAdvance:setSelected(1, MCGlobalAdvanceView)
	self:onToggleAdvance(1, MCGlobalAdvanceView)
	self.toggleAdvance:setSelected(1, MCGlobalAdvanceView)
	self.exclusiveSelection = containerData.exclusiveSelection[activeIndex] == nil and {Include={}, Exclude={}} or containerData.exclusiveSelection[activeIndex]
	--self.excludeRotten:setSelected(1, containerData.excludeRotten)

	for exclusiveType,itemList in pairs(self.exclusiveSelection) do
		self.advPanel:getView(exclusiveType).datas:clear()
		for itemName,_ in pairs(itemList) do
			local item = getScriptManager():getItem(itemName)
			self.advPanel:getView(exclusiveType).datas:addItem(item:getDisplayName(), item)
		end
	end


	self.categoryListBox:clearSelection()
	local listboxValues = containerData.containersFilters[activeIndex]
	if (listboxValues ~= nil) then
		self.categoryListBox:setSelectedByValues(listboxValues)
	end
end

function ISConfigureContainerWindow:update()
	local containerObj = self.containers:get(0):getParent()
	if self.character:DistTo(containerObj:getX(), containerObj:getY()) > self.closeWinDistance then
			self:setVisible(false);
			self:removeFromUIManager();
	end

	-- Update button label based on shift key state
	local isShiftDown = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) or Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)
	if self.lastCategoriesShiftState ~= isShiftDown then
		if isShiftDown then
			self.applyContainerItemCatButton:setTitle(getText("UI_AddCategoriesFromContainer"))
		else
			self.applyContainerItemCatButton:setTitle(getText("UI_SetCategoriesFromContainer"))
		end
		self.lastCategoriesShiftState = isShiftDown
	end
end

function ISConfigureContainerWindow:saveChanges(containerIndex)
	if self.prevContainersCount == 0 then return end
	if containerIndex == nil then containerIndex = self.panel:getActiveViewIndex() end

	local filterData = {}

	for _,selCat in ipairs(self.categoryListBox:getSelectedItems()) do
		table.insert(filterData, selCat.item)
	end
	local containerObj = self.containers:get(0)
	local parentContainer = containerObj:getParent()
	if parentContainer == nil then --It's possible the obj despawned because too far
		return
	end
	local modData = parentContainer:getModData()
	local containerKey = MCContainerDataPrefix .. self.playerContainerID
	if modData[containerKey] == nil then
		modData[containerKey] = {}
	end
	local previousName = modData[containerKey]["containerName"] == nil and "" or modData[containerKey]["containerName"]
	local claireEasterEgg = "give me rats"
	if modData[containerKey]["containersFilters"] == nil then
		modData[containerKey]["containersFilters"] = {}
	end
	if modData[containerKey]["exclusiveSelection"] == nil then
		modData[containerKey]["exclusiveSelection"] = {}
	end
	modData[containerKey]["containersFilters"][containerIndex] = filterData
	modData[containerKey]["exclusiveSelection"][containerIndex] = self.exclusiveSelection
	modData[containerKey]["containerName"] = self.textBoxName:getText()
	MCGlobalAdvanceView = self.toggleAdvance:isSelected(1)
	--modData[containerKey]["excludeRotten"] = self.excludeRotten:isSelected(1)

	if self.textBoxName:getText() == claireEasterEgg and previousName ~= claireEasterEgg then
		self.character:playSoundLocal("MCGiveMeRats")
		self.character:getInventory():AddItem("Base.Hat_Claire_Rat")
		modData[containerKey]["containerName"] = previousName
		self.textBoxName:setText(previousName)
	end

	parentContainer:transmitModData()
end

function ISConfigureContainerWindow:new(x, y, character, containers)
	local title = getText("ContextMenu_Configure_Container")
	local iconSpaceTitleRatio = 4.5
	local titlePadding = 20
	
	
	local simpleViewWidth = math.max(getTextManager():MeasureStringX(UIFont.Small, title) + (getTextManager():getFontHeight(UIFont.Small) * iconSpaceTitleRatio) + titlePadding, 250)
	local advanceViewWidth = 850 * self.UIScaleFactor()
	local height = 600 * self.UIScaleFactor()
	local o = ISCollapsableWindow:new(x, y, simpleViewWidth, height)
	setmetatable(o, self)
	self.__index = self
	o.simpleViewWidth = simpleViewWidth
	o.advanceViewWidth = advanceViewWidth
	o.title = title
	o.infoBtn = getTexture("media/ui/Panel_info_button.png")
	o.character = character
	o.playerNum = character:getPlayerNum()
	o.playerContainerID = self:getStoredUUID(character, "playerContainerID", true)
	o.containers = containers
	o.closeWinDistance = 10
	o.prevContainersCount = 0
	o.prevContainerSelection = 0
	o:setResizable(false)

	return o
end

function ISConfigureContainerWindow.UIScaleFactor()
	local fontSizeOption = getCore():getOptionFontSizeReal()
	local fontSizeMultipliers = { 1, 1, 1.2, 1.4, 1.6}
	return fontSizeMultipliers[math.min(fontSizeOption, 5)]
end

function ISConfigureContainerWindow:onMouseMove(dx, dy)
	ISCollapsableWindow.onMouseMove(self,dx,dy);
	getPlayer():setIgnoreAimingInput(self:isMouseOver() and not closingWindow);
end

function ISConfigureContainerWindow:onMouseMoveOutside(dx, dy)
	ISCollapsableWindow.onMouseMoveOutside(self,dx,dy);
	getPlayer():setIgnoreAimingInput(false);
end

function ISConfigureContainerWindow:getStoredUUID(isoObj, uuidName, createOnNil)
	--Used to be stored in the isoObj, but now these values should be fetched in a ini file
	createOnNil = createOnNil or false
	local storedData = LIP:load("\\manageContainers", "manageContainers.ini", createOnNil)
	local iniUUID = storedData.playerData ~= nil and storedData.playerData[uuidName] or nil
	local isoObjUUID = isoObj:getModData()[uuidName]

	-- If they are using the isoObj UUID, don't disturb it
	local storedUUID = isoObjUUID or iniUUID

	--Create new UUID
	if storedUUID == nil and createOnNil then
		storedUUID = getRandomUUID()
	elseif not createOnNil then
		return ''
	end

	if iniUUID == nil then
		LIP:save("\\manageContainers", "manageContainers.ini", {playerData={[uuidName]=storedUUID}})
	end
	if isoObjUUID == nil then
		isoObj:getModData()[uuidName] = storedUUID
	end

	return storedUUID
end

function ISConfigureContainerWindow:getContainerName(container)
	return getTextOrNull("IGUI_ContainerTitle_" .. container:getType())
end

function ISConfigureContainerWindow:fetchCategories(items)
	local cats = ArrayList.new()
	for i=0, items:size()-1 do
		local item = items:get(i)
		local category = item:getDisplayCategory()
		if category == nil then
			local itemInst = instanceItem(item)
			if itemInst ~= nil then
				category = itemInst:getDisplayCategory() or itemInst:getCategory()
			end
		end
		if category ~= nil and not cats:contains(category) then
			cats:add(category)
		end
	end
	return cats
end

function ISConfigureContainerWindow:onApplyContainerItemCat()
	-- Get the active container index (1-based from panel, convert to 0-based for ArrayList)
	local activeIndex = self.panel:getActiveViewIndex()
	
	-- Get the active container
	local container = self.containers:get(activeIndex - 1)
	if not container then
		return
	end
	
	-- Get all items from the container
	local containerItems = container:getItems()
	
	-- Fetch categories from those items
	local newCategories = self:fetchCategories(containerItems)
	
	-- Check if shift is held for add vs set mode
	local isShiftDown = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) or Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)
	
	if isShiftDown then
		-- Add mode: get current selected categories and merge with new ones
		local currentItems = self.categoryListBox:getSelectedItems()
		local resultList = {}
		
		-- Add current items to result
		for _, item in ipairs(currentItems) do
			table.insert(resultList, item.item)
		end
		
		-- Build set of existing categories for duplicate detection
		local existing = {}
		for _, item in ipairs(currentItems) do
			existing[item.item] = true
		end
		
		-- Add new categories that aren't already selected
		for i=0, newCategories:size()-1 do
			local category = newCategories:get(i)
			if not existing[category] then
				table.insert(resultList, category)
			end
		end
		
		self.categoryListBox:setSelectedByValues(resultList)
	else
		-- Set mode: replace entire selection with container categories
		local resultList = {}
		for i=0, newCategories:size()-1 do
			table.insert(resultList, newCategories:get(i))
		end
		self.categoryListBox:setSelectedByValues(resultList)
	end
end
