-- ------------- --
-- Price Tracker --
-- ------------- --

PriceTracker = {
	queryDelay = 3000,
	isSearching = false,
	settingsVersion = 0.2,
	icons = {
		gold = "EsoUI/Art/currency/currency_gold.dds"
	}
}
local PriceTracker = PriceTracker

-- Addon initialization
function PriceTracker:OnLoad(eventCode, addOnName)
	if(addOnName ~= "PriceTracker") then
		return
	end

	EVENT_MANAGER:RegisterForEvent("OnSearchResultsReceived", EVENT_TRADING_HOUSE_SEARCH_RESULTS_RECEIVED, function(...) self:OnSearchResultsReceived(...) end)
	EVENT_MANAGER:RegisterForEvent("OnTradingHouseClosed", EVENT_CLOSE_TRADING_HOUSE, function(...) self:OnTradingHouseClosed(...) end)

	ZO_PreHookHandler(ItemTooltip, "OnUpdate", function() self:OnUpdateTooltip(moc()) end)
	ZO_PreHookHandler(ItemTooltip, "OnHide", function() self:OnHideTooltip() end)

	SLASH_COMMANDS["/pt"] = function(...) self:CommandHandler(...) end
	SLASH_COMMANDS["/pricetracker"] = function(...) self:CommandHandler(...) end

	local defaults = {
		itemList = {},
		algorithm = self.menu.algorithmTable[1]
	}

	-- Load saved settings
	self.settings = ZO_SavedVars:NewAccountWide("PriceTrackerSettings", self.settingsVersion, nil, defaults)

	-- Create a button in the trading house window
	self.button = PriceTrackerControlButton
	self.button:SetParent(ZO_TradingHouseLeftPaneBrowseItemsCommon)
	self.button:SetWidth(ZO_TradingHouseLeftPaneBrowseItemsCommonQuality:GetWidth())

	self.menu:InitAddonMenu(addOnName)

end

-- Handle slash commands
function PriceTracker:CommandHandler(text)
	if not text or text == "" or text == "help" then
		self:ShowHelp()
		return
	end

	if text == "reset" or text == "clear" then
		self.settings.itemList = {}
		return
	end
end

function PriceTracker:ShowHelp()
	d("To scan all item prices in all guild stores, click the 'Scan Prices' button in the guild store window.")
	d(" ")
	d("/pt help - Show this help")
	d("/pt clear - Clear stored price values")
end

function PriceTracker:OnUpdateTooltip(item)
	if not item or not item.dataEntry or not item.dataEntry.data or self.selectedItem == item then
		return
	end

	self.selectedItem = item

	local matches = self:GetMatches(item.dataEntry.data.name)
	if not matches then
		return
	end

	local price = self:SuggestPrice(matches)
	if not price then
		return
	end

	ZO_Tooltip_AddDivider(ItemTooltip)
	ItemTooltip:AddLine("Price Tracker", "ZoFontHeader2")
	local r, g, b = ZO_TOOLTIP_DEFAULT_COLOR:UnpackRGB()
	local stackCount = item.dataEntry.data.stackCount or item.dataEntry.data.stack
	ItemTooltip:AddLine("Suggested Price: |r", "ZoFontGame", r, g, b, TOPLEFT, MODIFY_TEXT_TYPE_NONE, LEFT, false)
	ItemTooltip:AddLine(self:FormatTooltipLine("Item price: ", price, stackCount), "ZoFontGame", r, g, b, CENTER, MODIFY_TEXT_TYPE_NONE, CENTER, false)
	if stackCount > 1 then
		ItemTooltip:AddLine(self:FormatTooltipLine("Stack price: ", price * stackCount), "ZoFontGame", r, g, b, CENTER, MODIFY_TEXT_TYPE_NONE, CENTER, false)
	end
	if self.settings.showMinMax then
		ItemTooltip:AddLine(self:FormatTooltipLine("Min / Max: ", self.mathUtils:Min(matches) .. " / " .. self.mathUtils:Max(matches)), "ZoFontGame", r, g, b, CENTER, MODIFY_TEXT_TYPE_NONE, CENTER, false)
		ItemTooltip:AddLine(self:FormatTooltipLine("Min / Max (stack): ", self.mathUtils:Min(matches) * stackCount .. " / " .. self.mathUtils:Max(matches) * stackCount), "ZoFontGame", r, g, b, CENTER, MODIFY_TEXT_TYPE_NONE, CENTER, false)
	end
	if self.settings.showSeen then
		ItemTooltip:AddLine("Seen " .. #matches .. " times", "ZoFontGame", r, g, b, CENTER, MODIFY_TEXT_TYPE_NONE, CENTER, false)
	end
end

function PriceTracker:OnHideTooltip()
	self.selectedItem = nil
end

function PriceTracker:OnScanPrices()
	if self.isSearching then
		return
	end

	self.button:SetEnabled(false)
	self.isSearching = true
	self.numOfGuilds = GetNumTradingHouseGuilds()
	self.currentGuild = 0
	while not CanSellOnTradingHouse(self.currentGuild) and self.currentGuild < self.numOfGuilds do
		self.currentGuild = self.currentGuild + 1
	end

	zo_callLater(function() ExecuteTradingHouseSearch(0, TRADING_HOUSE_SORT_SALE_PRICE, true) end, self.queryDelay)
end

function PriceTracker:OnSearchResultsReceived(eventId, guildId, numItemsOnPage, currentPage, hasMorePages)
	if not self.isSearching then
		return
	end

	for i = 1, numItemsOnPage do
		self:AddItem(GetTradingHouseSearchResultItemInfo(i))
	end

	if hasMorePages then
		zo_callLater(function() ExecuteTradingHouseSearch(currentPage + 1, TRADING_HOUSE_SORT_SALE_PRICE, true) end, self.queryDelay)
	else
		if self.currentGuild < self.numOfGuilds then
			self.currentGuild = self.currentGuild + 1
			SelectTradingHouseGuildId(self.currentGuild)
			zo_callLater(function() ExecuteTradingHouseSearch(0, TRADING_HOUSE_SORT_SALE_PRICE, true) end, self.queryDelay)
		else
			self:OnTradingHouseClosed()
		end
	end
end

function PriceTracker:OnTradingHouseClosed()
	self.isSearching = false
	self.button:SetEnabled(true)
end

function PriceTracker:AddItem(icon, itemName, quality, stackCount, sellerName, timeRemaining, purchasePrice)
	local item = {}
	item.expiry = timeRemaining + GetTimeStamp()
	item.icon = icon
	item.name = itemName
	item.normalizedName = self:NormalizeName(itemName)
	item.quality = quality
	item.stackCount = stackCount
	item.sellerName = sellerName
	item.purchasePrice = purchasePrice
	item.guildId = self.currentGuild
	item.guildName = GetGuildName(item.guildId)

	if not self.settings.itemList[item.normalizedName] then
		self.settings.itemList[item.normalizedName] = {}
	end

	-- Do not add items that are already in the database
	if not self.settings.itemList[item.normalizedName][item.expiry] then
		self.settings.itemList[item.normalizedName][item.expiry] = item
	end
end

function PriceTracker:GetMatches(itemName)
	local normalizedName = self:NormalizeName(itemName)
	if not self.settings.itemList or not self.settings.itemList[normalizedName] then
		return nil
	end

	local index = next(self.settings.itemList[normalizedName])
	if index == nil then
		return nil
	end

	local matches = {}
	while index do
		table.insert(matches, self.settings.itemList[normalizedName][index])
		index = next(self.settings.itemList[normalizedName], index)
	end

	self.matches = matches
	return matches
end

-- TODO: Base calculation on user preference
function PriceTracker:SuggestPrice(matches)
	if self.settings.algorithm == self.menu.algorithmTable[1] then
		return self.mathUtils:WeightedAverage(matches)
	end

	if self.settings.algorithm == self.menu.algorithmTable[2] then
		return self.mathUtils:Median(matches)
	end

	if self.settings.algorithm == self.menu.algorithmTable[3] then
		return self.mathUtils:Mode(matches)
	end

	d("Error deciding how to calculate suggested price")
	return nil
end

function PriceTracker:FormatTooltipLine(title, price, stackCount)
	return string.format("%-30s %7s%s", title, price, zo_iconFormat(self.icons.gold, 16, 16))
end

function PriceTracker:NormalizeName(name)
	return zo_strformat(SI_TOOLTIP_ITEM_NAME, name)
end

EVENT_MANAGER:RegisterForEvent("PriceTrackerLoaded", EVENT_ADD_ON_LOADED, function(...) PriceTracker:OnLoad(...) end)