local L = BAGSYNC_L
local searchTable = {}
local rows, anchor = {}
local currentRealm = GetRealmName()
local GetItemInfo = _G['GetItemInfo']
local currentPlayer = UnitName('player')

local ItemSearch = LibStub('LibItemSearch-1.0')
local bgSearch = CreateFrame("Frame","BagSync_SearchFrame", UIParent)

--add class search
local tooltipScanner = _G['LibItemSearchTooltipScanner'] or CreateFrame('GameTooltip', 'LibItemSearchTooltipScanner', UIParent, 'GameTooltipTemplate')
local tooltipCache = setmetatable({}, {__index = function(t, k) local v = {} t[k] = v return v end})

ItemSearch:RegisterTypedSearch{
	id = 'classRestriction',
	tags = {'c', 'class'},
	
	canSearch = function(self, _, search)
		return search
	end,
	
	findItem = function(self, link, _, search)
		if link:find("battlepet") then return false end

		local itemID = link:match('item:(%d+)')
		if not itemID then
			return
		end
		
		local cachedResult = tooltipCache[search][itemID]
		if cachedResult ~= nil then
			return cachedResult
		end
	
		tooltipScanner:SetOwner(UIParent, 'ANCHOR_NONE')
		tooltipScanner:SetHyperlink(link)

		local result = false
		
		local pattern = string.gsub(ITEM_CLASSES_ALLOWED:lower(), "%%s", "(.+)")
		
		for i = 1, tooltipScanner:NumLines() do
			local text =  _G[tooltipScanner:GetName() .. 'TextLeft' .. i]:GetText():lower()
			local textChk = string.find(text, pattern)

			if textChk and tostring(text):find(search) then
				result = true
			end
		end
		
		tooltipCache[search][itemID] = result
		return result
	end,
}

local function LoadSlider()

	local function OnEnter(self)
		if self.link then
			GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT")
			GameTooltip:SetHyperlink(self.link)
			GameTooltip:Show()
		end
	end
	local function OnLeave() GameTooltip:Hide() end

	local EDGEGAP, ROWHEIGHT, ROWGAP, GAP = 16, 20, 2, 4
	local FRAME_HEIGHT = bgSearch:GetHeight() - 60
	local SCROLL_TOP_POSITION = -90
	local totalRows = math.floor((FRAME_HEIGHT-22)/(ROWHEIGHT + ROWGAP))
	
	for i=1, totalRows do
		if not rows[i] then
			local row = CreateFrame("Button", "BagSyncSearchRow"..i, bgSearch)
			if not anchor then row:SetPoint("BOTTOMLEFT", bgSearch, "TOPLEFT", 0, SCROLL_TOP_POSITION)
			else row:SetPoint("TOP", anchor, "BOTTOM", 0, -ROWGAP) end
			row:SetPoint("LEFT", EDGEGAP, 0)
			row:SetPoint("RIGHT", -EDGEGAP*2-8, 0)
			row:SetHeight(ROWHEIGHT)
			row:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
			anchor = row
			rows[i] = row

			local title = row:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
			title:SetPoint("LEFT")
			title:SetJustifyH("LEFT") 
			title:SetWidth(row:GetWidth())
			title:SetHeight(ROWHEIGHT)
			row.title = title

			row:SetScript("OnEnter", OnEnter)
			row:SetScript("OnLeave", OnLeave)
			row:SetScript("OnClick", function(self)
				if self.link then
					if HandleModifiedItemClick(self.link) then
						return
					end
					if IsModifiedClick("CHATLINK") then
						local editBox = ChatEdit_ChooseBoxForSend()
						if editBox then
							editBox:Insert(self.link)
							ChatFrame_OpenChat(editBox:GetText())
						end
					end
				end
			end)
		end
	end

	local offset = 0
	local RefreshSearch = function()
		if not BagSync_SearchFrame:IsVisible() then return end
		for i,row in ipairs(rows) do
			if (i + offset) <= #searchTable then
				if searchTable[i + offset] then
					if searchTable[i + offset].rarity then
						--local hex = (select(4, GetItemQualityColor(searchTable[i + offset].rarity)))
						local hex = (select(4, GetItemQualityColor(searchTable[i + offset].rarity)))
						row.title:SetText(format('|c%s%s|r', hex, searchTable[i + offset].name) or searchTable[i + offset].name)
					else
						row.title:SetText(searchTable[i + offset].name)
					end
					row.link = searchTable[i + offset].link
					row:Show()
				end
			else
				row.title:SetText(nil)
				row:Hide()
			end
		end
	end

	RefreshSearch()

	if not bgSearch.scrollbar then
		bgSearch.scrollbar = LibStub("tekKonfig-Scroll").new(bgSearch, nil, #rows/2)
		bgSearch.scrollbar:ClearAllPoints()
		bgSearch.scrollbar:SetPoint("TOP", rows[1], 0, -16)
		bgSearch.scrollbar:SetPoint("BOTTOM", rows[#rows], 0, 16)
		bgSearch.scrollbar:SetPoint("RIGHT", -16, 0)
	end
	
	if #searchTable > 0 then
		bgSearch.scrollbar:SetMinMaxValues(0, math.max(0, #searchTable - #rows))
		bgSearch.scrollbar:SetValue(0)
		bgSearch.scrollbar:Show()
	else
		bgSearch.scrollbar:Hide()
	end
	
	local f = bgSearch.scrollbar:GetScript("OnValueChanged")
		bgSearch.scrollbar:SetScript("OnValueChanged", function(self, value, ...)
		offset = math.floor(value)
		RefreshSearch()
		return f(self, value, ...)
	end)

	bgSearch:EnableMouseWheel()
	bgSearch:SetScript("OnMouseWheel", function(self, val)
		bgSearch.scrollbar:SetValue(bgSearch.scrollbar:GetValue() - val*#rows/2)
	end)
end

--do search routine
local function DoSearch()
	if not BagSync or not BagSyncDB then return end
	local searchStr = bgSearch.SEARCHBTN:GetText()

	searchStr = searchStr:lower()
	
	searchTable = {} --reset
	
	local tempList = {}
	local previousGuilds = {}
	local count = 0
	local playerSearch = false
	
	if strlen(searchStr) > 0 then
		
		local playerFaction = UnitFactionGroup("player")
		local allowList = {
			["bag"] = 0,
			["bank"] = 0,
			["equip"] = 0,
			["mailbox"] = 0,
			["void"] = 0,
			["auction"] = 0,
			["guild"] = 0,
			["reagentbank"] = 0,
		}
		
		if string.len(searchStr) > 1 and string.find(searchStr, "@") and allowList[string.sub(searchStr, 2)] ~= nil then playerSearch = true end
		
		--loop through our characters
		--k = player, v = stored data for player
		for k, v in pairs(BagSyncDB[currentRealm]) do

			local pFaction = v.faction or playerFaction --just in case ;) if we dont know the faction yet display it anyways
			
			--check if we should show both factions or not
			if BagSyncOpt.enableFaction or pFaction == playerFaction then

				--now count the stuff for the user
				--q = bag name, r = stored data for bag name
				for q, r in pairs(v) do
					--only loop through table items we want
					if allowList[q] and type(r) == "table" then
						--bagID = bag name bagID, bagInfo = data of specific bag with bagID
						for bagID, bagInfo in pairs(r) do
							--slotID = slotid for specific bagid, itemValue = data of specific slotid
							if type(bagInfo) == "table" then
								for slotID, itemValue in pairs(bagInfo) do
									local dblink, dbcount = strsplit(',', itemValue)
									if dblink then
										local dName, dItemLink, dRarity = GetItemInfo(dblink)
										if dName and dItemLink then
											--are we checking in our bank,void, etc?
											if playerSearch and string.sub(searchStr, 2) == q and string.sub(searchStr, 2) ~= "guild" and k == currentPlayer and not tempList[dblink] then
												table.insert(searchTable, { name=dName, link=dItemLink, rarity=dRarity } )
												tempList[dblink] = dName
												count = count + 1
											--we found a match
											elseif not playerSearch and not tempList[dblink] and ItemSearch:Find(dItemLink, searchStr) then
												table.insert(searchTable, { name=dName, link=dItemLink, rarity=dRarity } )
												tempList[dblink] = dName
												count = count + 1
											end
										end
									end
								end
							end
						end
					end
				end
				
				if BagSyncOpt.enableGuild then
					local guildN = v.guild or nil
				
					--check the guild bank if the character is in a guild
					if BagSyncGUILD_DB and guildN and BagSyncGUILD_DB[currentRealm][guildN] then
						--check to see if this guild has already been done through this run (so we don't do it multiple times)
						if not previousGuilds[guildN] then
							--we only really need to see this information once per guild
							for q, r in pairs(BagSyncGUILD_DB[currentRealm][guildN]) do
								local dblink, dbcount = strsplit(',', r)
								if dblink then
									local dName, dItemLink, dRarity = GetItemInfo(dblink)
									if dName then
										if playerSearch and string.sub(searchStr, 2) == q and string.sub(searchStr, 2) == "guild" and k == currentPlayer and not tempList[dblink] then
											table.insert(searchTable, { name=dName, link=dItemLink, rarity=dRarity } )
											tempList[dblink] = dName
											count = count + 1
										--we found a match
										elseif not playerSearch and not tempList[dblink] and ItemSearch:Find(dItemLink, searchStr) then
											table.insert(searchTable, { name=dName, link=dItemLink, rarity=dRarity } )
											tempList[dblink] = dName
											count = count + 1
										end
									end
								end
							end
							previousGuilds[guildN] = true
						end
					end
				end
				
			end
			
		end
		
		table.sort(searchTable, function(a,b) return (a.name < b.name) end)
	end
	
	bgSearch.totalC:SetText("|cFFFFFFFF"..L["Total:"].." "..count.."|r")
	
	LoadSlider()
end

local function escapeEditBox(self)
  self:SetAutoFocus(false)
end

local function enterEditBox(self)
	self:ClearFocus()
	--self:GetParent():DoSearch()
	DoSearch()
end

local function createEditBox(name, labeltext, obj, x, y)
  local editbox = CreateFrame("EditBox", name, obj, "InputBoxTemplate")
  editbox:SetAutoFocus(false)
  editbox:SetWidth(180)
  editbox:SetHeight(16)
  editbox:SetPoint("TOPLEFT", obj, "TOPLEFT", x or 0, y or 0)
  local label = editbox:CreateFontString(nil, "ARTWORK", "GameFontNormal")
  label:SetPoint("BOTTOMLEFT", editbox, "TOPLEFT", -6, 4)
  label:SetText(labeltext)
  editbox:SetScript("OnEnterPressed", enterEditBox)
  editbox:HookScript("OnEscapePressed", escapeEditBox)
  return editbox
end

bgSearch:SetFrameStrata("HIGH")
bgSearch:SetToplevel(true)
bgSearch:EnableMouse(true)
bgSearch:SetMovable(true)
bgSearch:SetClampedToScreen(true)
bgSearch:SetWidth(380)
bgSearch:SetHeight(500)

bgSearch:SetBackdrop({
		bgFile = "Interface/Tooltips/UI-Tooltip-Background",
		edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = true,
		tileSize = 16,
		edgeSize = 32,
		insets = { left = 5, right = 5, top = 5, bottom = 5 }
})

bgSearch:SetBackdropColor(0,0,0,1)
bgSearch:SetPoint("CENTER", UIParent, "CENTER", 0, 0)

bgSearch.SEARCHBTN = createEditBox("$parentEdit1", (L["Search"]..":"), bgSearch, 60, -50)

local addonTitle = bgSearch:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
addonTitle:SetPoint("CENTER", bgSearch, "TOP", 0, -20)
addonTitle:SetText("|cFF99CC33BagSync|r |cFFFFFFFF("..L["Search"]..")|r")

local totalC = bgSearch:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
totalC:SetPoint("RIGHT", bgSearch.SEARCHBTN, 70, 0)
totalC:SetText("|cFFFFFFFF"..L["Total:"].." 0|r")
bgSearch.totalC = totalC
		
local closeButton = CreateFrame("Button", nil, bgSearch, "UIPanelCloseButton");
closeButton:SetPoint("TOPRIGHT", bgSearch, -15, -8);

bgSearch:SetScript("OnShow", function(self)
	LoadSlider()
	self.SEARCHBTN:SetFocus()
end)
bgSearch:SetScript("OnHide", function(self)
	searchTable = {}
	self.SEARCHBTN:SetText("")
	self.totalC:SetText("|cFFFFFFFF"..L["Total:"].." 0|r")
end)

bgSearch:SetScript("OnMouseDown", function(frame, button)
	if frame:IsMovable() then
		frame.isMoving = true
		frame:StartMoving()
	end
end)

bgSearch:SetScript("OnMouseUp", function(frame, button) 
	if( frame.isMoving ) then
		frame.isMoving = nil
		frame:StopMovingOrSizing()
	end
end)

function bgSearch:initSearch()
	DoSearch()
end

bgSearch:Hide()
