ProfessionsQualityDialogMixin = CreateFromMixins(CallbackRegistryMixin);

ProfessionsQualityDialogMixin:GenerateCallbackEvents(
{
    "Accepted",
});

function ProfessionsQualityDialogMixin:OnLoad()
	CallbackRegistryMixin.OnLoad(self);

	self:SetTitle(PROFESSIONS_QUALITY_DIALOG_TITLE);

	self.containers = {self.Container1, self.Container2, self.Container3};

	local function GetQuantityOutstanding(qualityIndex)
		return self:GetQuantityRequired() - (self:Accumulate() - self:GetQuantityAllocated(qualityIndex));
	end
	
	local function Allocate(qualityIndex, value)
		value = math.min(value, ProfessionsUtil.GetReagentQuantityInPossession(self:GetReagent(qualityIndex), self.characterInventoryOnly));

		self.allocations:Allocate(self:GetReagent(qualityIndex), value);
		
		local overflow = math.max(0, self:Accumulate() - self:GetQuantityRequired());
		if overflow > 0 then
			for deallocateIndex = 1, self:GetReagentSlotCount() do
				if deallocateIndex ~= qualityIndex then
					local reagent = self:GetReagent(deallocateIndex);
					local oldQuantity = self.allocations:GetQuantityAllocated(reagent);
					local deallocatable = math.min(overflow, oldQuantity);
					if deallocatable > 0 then
						overflow = overflow - deallocatable;

						local newQuantity = oldQuantity - deallocatable;
						self.allocations:Allocate(reagent, newQuantity);
					end
				end

				if overflow <= 0 then
					break;
				end
			end
		end

		for reagentIndex = 1, self:GetReagentSlotCount() do
			local container = self.containers[reagentIndex];
			local editBox = container.EditBox;
			local reagent = self:GetReagent(reagentIndex);
			local quantity = self.allocations:GetQuantityAllocated(reagent);
			editBox:SetValue(quantity);
		end

		self:EvaluateAllocations();
		return value;
	end

	for containerIndex, container in ipairs(self.containers) do
		local editBox = container.EditBox;

		local function ApplyEditBoxText(editBox)
			Allocate(containerIndex, math.min(self:GetQuantityRequired(), tonumber(editBox:GetText()) or 0));
		end

		editBox:SetScript("OnEnterPressed", ApplyEditBoxText);
		editBox:SetScript("OnEditFocusLost", ApplyEditBoxText);
		editBox:SetScript("OnTextChanged", function(editBox, userChanged)
			if not userChanged then
				Allocate(containerIndex, tonumber(editBox:GetText()) or 0);
			end
		end);

		local button = container.Button;
		button:SetScript("OnClick", function(button, buttonName, down)
			if IsShiftKeyDown() then
				Professions.HandleQualityReagentLink(self.recipeID, self.reagentSlotSchematic, containerIndex);
			else
				if buttonName == "LeftButton" then
					Allocate(containerIndex, self:GetQuantityRequired());
				elseif buttonName == "RightButton" then
					Allocate(containerIndex, 0)
				end
			end
		end);

		button:SetScript("OnEnter", function()
			GameTooltip:SetOwner(button, "ANCHOR_TOPLEFT");
			local reagent = self:GetReagent(containerIndex);
			Professions.SetupReagentTooltip(reagent);
			GameTooltip:Show();
		end);

		button:SetScript("OnLeave", function()
			GameTooltip:Hide();
		end);
	end
	
	self.onCloseCallback = function(button)
		PlaySound(SOUNDKIT.UI_PROFESSION_QUALITY_DIALOG_EXIT);
		return true;
	end
	
	local function OnCancel()
		self:Hide();
		PlaySound(SOUNDKIT.UI_PROFESSION_QUALITY_DIALOG_EXIT);
	end

	self.CancelButton:SetText(CANCEL);
	self.CancelButton:SetScript("OnClick", OnCancel);

	self.AcceptButton:SetText(ACCEPT);
	self.AcceptButton:SetScript("OnClick", function(button, buttonName, down)
		self:TriggerEvent(ProfessionsQualityDialogMixin.Event.Accepted, self.allocations, self.reagentSlotSchematic);
		self:Hide();
		PlaySound(SOUNDKIT.UI_PROFESSION_QUALITY_DIALOG_CONFIRM);
	end);
end

function ProfessionsQualityDialogMixin:OnHide()
	self:UnregisterEvents();
	self.reagentSlotSchematic = nil;
	self.recipeID = nil;
	self.allocations = nil;
end

function ProfessionsQualityDialogMixin:GetReagent(qualityIndex)
	return self.reagentSlotSchematic.reagents[qualityIndex];
end

function ProfessionsQualityDialogMixin:GetReagentSlotCount()
	return #self.reagentSlotSchematic.reagents;
end

function ProfessionsQualityDialogMixin:Init(recipeID, reagentSlotSchematic, allocations, slotIndex, disallowZeroAllocations, characterInventoryOnly)
	self.reagentSlotSchematic = reagentSlotSchematic;
	self.recipeID = recipeID;
	self.slotIndex = slotIndex;
	self.allocations = allocations;
	self.disallowZeroAllocations = disallowZeroAllocations;
	self.characterInventoryOnly = characterInventoryOnly;

	self:Setup();
end

function ProfessionsQualityDialogMixin:ReinitAllocations(allocations)
	self.allocations = allocations;
	self:Setup();
end

function ProfessionsQualityDialogMixin:Setup()
	for index, container in ipairs(self.containers) do
		container:Hide();
	end

	local totalWidth = 0;

	for qualityIndex, reagent in ipairs(self.reagentSlotSchematic.reagents) do
		local container = self.containers[qualityIndex];
		container:Show();

		local button = container.Button;
		button:SetReagent(reagent);

		-- The min and max values will be recalculated after our initial values are set.
		local editBox = container.EditBox;
		editBox:SetMinMaxValues(0, math.huge);

		local quantity = self:GetQuantityAllocated(qualityIndex);
		editBox:SetText(quantity);

		local count = ProfessionsUtil.GetReagentQuantityInPossession(reagent, self.characterInventoryOnly);
		button:SetItemButtonCount(count);

		local enabled = count > 0;
		button:DesaturateHierarchy(enabled and 0 or 1);
		editBox:SetEnabled(enabled);

		totalWidth = totalWidth + container:GetWidth();
	end

	local firstContainer = self.containers[1];
	local x = -(totalWidth / 2) + (firstContainer:GetWidth() / 2) + 5;
	firstContainer:SetPoint("CENTER", self, "CENTER", x, 0);

	self:EvaluateAllocations();
end

function ProfessionsQualityDialogMixin:GetSlotIndex()
	return self.slotIndex;
end

function ProfessionsQualityDialogMixin:Open(recipeID, reagentSlotSchematic, allocations, slotIndex, disallowZeroAllocations, characterInventoryOnly)
	self:Init(recipeID, reagentSlotSchematic, allocations, slotIndex, disallowZeroAllocations, characterInventoryOnly);
	self:Show();
end

function ProfessionsQualityDialogMixin:Close()
	self:Hide();
end

function ProfessionsQualityDialogMixin:Accumulate()
	return self.allocations:Accumulate();
end

function ProfessionsQualityDialogMixin:GetQuantityAllocated(qualityIndex)
	return self.allocations:GetQuantityAllocated(self:GetReagent(qualityIndex));
end

function ProfessionsQualityDialogMixin:GetQuantityRequired()
	return self.reagentSlotSchematic.quantityRequired;
end

function ProfessionsQualityDialogMixin:EvaluateAllocations()
	local quantityRequired = self:GetQuantityRequired();
	local quantityAllocated = self:Accumulate();

	for qualityIndex, reagent in ipairs(self.reagentSlotSchematic.reagents) do
		local container = self.containers[qualityIndex];
		local editBox = container.EditBox;
		editBox:SetMinMaxValues(0, math.min(self:GetQuantityRequired(), ProfessionsUtil.GetReagentQuantityInPossession(reagent, self.characterInventoryOnly)));
	end

	local canEnable = not self.disallowZeroAllocations and quantityAllocated == 0;
	self.AcceptButton:SetEnabled(canEnable or quantityAllocated >= quantityRequired);
end
