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

PriceTracker = {
	queryDelay = 3000,
	isSearching = false,
	settingsVersion = 0.1,
	mathUtils = MathUtils
}

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 = {}
	}

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

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

	-- Create a money icon
	-- PriceTracker.moneyIcon = ItemTooltip:CreateControl("moneyIcon", CT_TEXTURE)

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
		PriceTracker.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 PriceTracker.selectedItem == item then
		return
	end

	PriceTracker.selectedItem = item

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

	ZO_Tooltip_AddDivider(ItemTooltip)
	ItemTooltip:AddLine("Price Tracker", "ZoFontHeader2")
	local r, g, b = ZO_TOOLTIP_DEFAULT_COLOR:UnpackRGB()
	ItemTooltip:AddLine("Suggested Price:", "ZoFontGame", r, g, b, TOPLEFT, MODIFY_TEXT_TYPE_NONE, LEFT, false)
	ItemTooltip:AddLine(self:FormatTooltipLine(self:FormatPrice(price), item.dataEntry.data.stackCount or item.dataEntry.data.stack), "ZoFontGame", r, g, b, LEFT, MODIFY_TEXT_TYPE_NONE, CENTER, false)
end

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

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

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

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

function PriceTracker:OnSearchResultsReceived(eventId, guildId, numItemsOnPage, currentPage, hasMorePages)
	if not PriceTracker.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, PriceTracker.queryDelay)
	else
		if PriceTracker.currentGuild < PriceTracker.numOfGuilds then
			PriceTracker.currentGuild = PriceTracker.currentGuild + 1
			SelectTradingHouseGuildId(PriceTracker.currentGuild)
			zo_callLater(function() ExecuteTradingHouseSearch(0, TRADING_HOUSE_SORT_SALE_PRICE, true) end, PriceTracker.queryDelay)
		else
			self:OnTradingHouseClosed()
		end
	end
end

function PriceTracker:OnTradingHouseClosed()
	PriceTracker.isSearching = false
	PriceTracker.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 = PriceTracker.currentGuild
	item.guildName = GetGuildName(item.guildId)

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

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

-- TODO: Base calculation on user preference
function PriceTracker:SuggestPrice(itemName)
	local normalizedName = self:NormalizeName(itemName)
	if not PriceTracker.settings.itemList or not PriceTracker.settings.itemList[normalizedName] then
		return nil
	end

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

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

	PriceTracker.matches = matches

	local sum = 0
	local weight = 0
	for i = 1, #matches do
		sum = sum + matches[i].purchasePrice
		weight = weight + matches[i].stackCount
	end
	return sum / weight
	-- return PriceTracker.mathUtils:WeightedAverage(matches)
end

-- Format the price into a more-readable string. Omit decimal point if price is an integer
function PriceTracker:FormatPrice(price)
	if(math.floor(price) == price) then
		return price
	end

	return string.format("%.2f", price)
end

function PriceTracker:FormatTooltipLine(price, stackCount)
	return string.format("%7s|t16:16:%s|t %-25s %7s|t16:16:%s|t %-25s", price, "EsoUI/Art/currency/currency_gold.dds", "(per item)", price * stackCount, "EsoUI/Art/currency/currency_gold.dds", "(stack of " .. stackCount .. ")")
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)