local E, L, V, P, G = unpack(select(2, ...)); -- Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local mod = E:GetModule('NamePlates_v1')
local LSM = E.Libs.LSM

-- Lua functions
local _G = _G
local pairs = pairs
local unpack = unpack
local floor = math.floor
local match = string.match
-- WoW API / Variables
local CreateFrame = CreateFrame
local IsInInstance = IsInInstance
local GetQuestLogTitle = GetQuestLogTitle
local GetQuestLogIndexByID = GetQuestLogIndexByID
local GetQuestLogSpecialItemInfo = GetQuestLogSpecialItemInfo
local C_TaskQuest_GetQuestProgressBarInfo = C_TaskQuest.GetQuestProgressBarInfo
local ThreatTooltip = THREAT_TOOLTIP:gsub('%%d', '%%d-')

mod.ActiveQuests = {
    -- [questName] = questID ?
}

local UsedLocale = GetLocale()
local QuestTypesLocalized = {
    ["enUS"] = {
        ["slain"] = "KILL",
        ["destroy"] = "KILL",
        ["kill"] = "KILL",
        ["defeat"] = "KILL",
        ["speak"] = "CHAT"
    },
    ["zhCN"] = {
        ["消灭"] = "KILL",["摧毁"] = "KILL",["获得"] = "KILL",
        ["击败"] = "KILL",["被杀"] = "KILL",["毁灭"] = "KILL",
        ["击退"] = "KILL",["杀死"] = "KILL",
        ["交谈"] = "CHAT",["说话"] = "CHAT",
        ["询问"] = "CHAT",["建立"] = "CHAT"
    },
    ["zhTW"] = {
        ["被殺"] = "KILL", ["毀滅"] = "KILL", ["消除"] = "KILL", ["擊退"] = "KILL", ["殺死"] = "KILL", ["打败"] = "KILL", 
        ["說話"] = "CHAT", ["詢問"] = "CHAT", ["交談"] = "CHAT", ["建立"] = "CHAT", ["建设"] = "CHAT"
    }
}

local QuestTypes = QuestTypesLocalized[UsedLocale] or
                       QuestTypesLocalized["enUS"]

function mod:QUEST_ACCEPTED(_, questLogIndex, questID)
    if questLogIndex and questLogIndex > 0 then
        local questName = GetQuestLogTitle(questLogIndex)

        if questName and (questID and questID > 0) then
            self.ActiveQuests[questName] = questID
        end

        mod:ForEachPlate("UpdateElement_QuestIcon")
    end
end

function mod:QUEST_REMOVED(_, questID)
    if not questID then return end
    for questName, __questID in pairs(self.ActiveQuests) do
        if __questID == questID then
            self.ActiveQuests[questName] = nil
            mod:ForEachPlate("UpdateElement_QuestIcon")
            break
        end
    end
end

mod.QuestObjectiveStrings = {}
function mod:QUEST_LOG_UPDATE() mod:ForEachPlate("UpdateElement_QuestIcon") end

local function CheckTextForQuest(text)
    local x, y = strmatch(text, '(%d+)/(%d+)')
    if x and y then
        return true
    elseif not strmatch(text, ThreatTooltip) then
        local progress = tonumber(strmatch(text, '([%d%.]+)%%'))
        if progress and progress <= 100 then
            if (string.find(text, '威胁') ~= nil) then
                return false
            else
                return true
            end
        else
            return false
        end
    end
end

function mod:GetQuests(unitID)
    local inInstance = IsInInstance()
    if inInstance then return end

    E.ScanTooltip:SetOwner(_G.UIParent, "ANCHOR_NONE")
    E.ScanTooltip:SetUnit(unitID)
    E.ScanTooltip:Show()

    local QuestList, notMyQuest
    for i = 3, E.ScanTooltip:NumLines() do
        -- local num1,num2=math.modf(i/2)--返回整数和小数部分
        local str = _G['ElvUI_ScanTooltipTextLeft' .. i]
        local text = str and str:GetText()
        if not text or text == '' then return end -- 获取文本
		
        local isQuestText = CheckTextForQuest(text)
        if isQuestText then
			-- dosomething
			local _j = i - 1
			local _str = _G['ElvUI_ScanTooltipTextLeft' .. _j]
            local _text = _str and _str:GetText() --获取上一行的文本
			
			if UnitIsPlayer(_text) then --如果不是玩家名称，则是任务名称文本
				local ismySelf = _text == E.myname
				if ismySelf then
					_j = _j - 1
					_str = _G['ElvUI_ScanTooltipTextLeft' .. _j]
                    _text = _str and _str:GetText() --再往上获取一行，该行即为任务名称行
                    local objCount, QuestType, IsPerc, logIndex, itemTex, _

                    -- active quest
                    local QuestID = self.ActiveQuests[_text]
                    
                    
                    if QuestID then
                        -- print(E.ScanTooltip:NumLines())
                        logIndex = GetQuestLogIndexByID(QuestID)
                        _, itemTex = GetQuestLogSpecialItemInfo(logIndex)
        
                        local progress = C_TaskQuest_GetQuestProgressBarInfo(QuestID)
                        if progress then
                            objCount = floor(progress)
                            IsPerc = true
                        end
                    else
                        -- print(text)
                    end
                    
                    
                    -- text check, only if active quest doesnt find the objective
                    if not objCount then
                        if text then
                            local x, y = strmatch(text, '(%d+)/(%d+)')
                            if x and y then
                                objCount = floor(y - x)
                            elseif not strmatch(text, ThreatTooltip) then
                                local progress = tonumber(strmatch(text, '([%d%.]+)%%'))
                                if progress and progress < 100 then
                                    objCount = ceil(progress)
                                    IsPerc = true
                                end
                            end
                        end
                    end
        
                    if itemTex then
                        QuestType = "QUEST_ITEM"
                    elseif objCount then
                        QuestType = "LOOT"
        
                        local lowerText = text:lower()
                        for questString in pairs(QuestTypes) do
                            if strfind(lowerText, questString) then
                                QuestType = QuestTypes[questString]
                                break
                            end
                        end
                    end
        
                    if QuestType then
                        if not QuestList then QuestList = {} end
                        QuestList[#QuestList + 1] =
                            {
                                isPerc = IsPerc,
                                itemTexture = itemTex,
                                objectiveCount = objCount,
                                questType = QuestType,
                                -- below keys are currently unused
                                questLogIndex = logIndex,
                                questID = QuestID
                            }
                    end
                else
				--是别的玩家名，跳过判断，不执行任何操作
                end
            else
                --不是玩家名称，直接判定为任务名称
                local objCount, QuestType, IsPerc, logIndex, itemTex, _

                -- active quest
                local QuestID = self.ActiveQuests[_text]
                
                
                if QuestID then
                    -- print(E.ScanTooltip:NumLines())
                    logIndex = GetQuestLogIndexByID(QuestID)
                    _, itemTex = GetQuestLogSpecialItemInfo(logIndex)
    
                    local progress = C_TaskQuest_GetQuestProgressBarInfo(QuestID)
                    if progress then
                        objCount = floor(progress)
                        IsPerc = true
                    end
                else
                    -- print(text)
                end
                
                
                -- text check, only if active quest doesnt find the objective
                if not objCount then
                    if text then
                        local x, y = strmatch(text, '(%d+)/(%d+)')
                        if x and y then
                            objCount = floor(y - x)
                        elseif not strmatch(text, ThreatTooltip) then
                            local progress = tonumber(strmatch(text, '([%d%.]+)%%'))
                            if progress and progress < 100 then
                                objCount = ceil(progress)
                                IsPerc = true
                            end
                        end
                    end
                end
    
                if itemTex then
                    QuestType = "QUEST_ITEM"
                elseif objCount then
                    QuestType = "LOOT"
    
                    local lowerText = text:lower()
                    for questString in pairs(QuestTypes) do
                        if strfind(lowerText, questString) then
                            QuestType = QuestTypes[questString]
                            break
                        end
                    end
                end
    
                if QuestType then
                    if not QuestList then QuestList = {} end
                    QuestList[#QuestList + 1] =
                        {
                            isPerc = IsPerc,
                            itemTexture = itemTex,
                            objectiveCount = objCount,
                            questType = QuestType,
                            -- below keys are currently unused
                            questLogIndex = logIndex,
                            questID = QuestID
                        }
                end
			end
        end
    end
    E.ScanTooltip:Hide()

    return QuestList
end

function mod:Get_QuestIcon(frame, index)
    if frame.QuestIcon[index] then return frame.QuestIcon[index] end

    local iconSize = self.db.questIconSize
    local icon = CreateFrame("Frame", nil, frame.QuestIcon)
    icon:SetSize(iconSize, iconSize)

    if index == 1 then
        icon:SetPoint("LEFT", frame.QuestIcon, "LEFT")
    else
        icon:SetPoint("LEFT", frame.QuestIcon[index - 1], "RIGHT", 2, 0)
    end

    -- Usable Quest icons
    local itemTexture = icon:CreateTexture(nil, 'BORDER', nil, 1)
    itemTexture:SetPoint('TOPRIGHT', icon, 'BOTTOMLEFT', 12, 12)
    itemTexture:SetSize(iconSize, iconSize)
    itemTexture:SetTexCoord(unpack(E.TexCoords))
    itemTexture:Hide()
    icon.ItemTexture = itemTexture

    -- Loot icon, display if mob needs to be looted for quest item
    local lootIcon = icon:CreateTexture(nil, 'BORDER', nil, 1)
    lootIcon:SetAtlas('Banker')
    lootIcon:SetSize(iconSize, iconSize)
    lootIcon:SetPoint('TOPLEFT', icon, 'TOPLEFT')
    lootIcon:Hide()
    icon.LootIcon = lootIcon

    -- Skull icon, display if mob needs to be slain
    local skullIcon = icon:CreateTexture(nil, 'BORDER', nil, 1)
    skullIcon:SetAtlas('DungeonSkull')
    skullIcon:SetSize(iconSize, iconSize)
    skullIcon:SetPoint('TOPLEFT', icon, 'TOPLEFT')
    -- skullIcon:SetTexture(E.Media.Textures.SkullIcon)
    skullIcon:Hide()
    icon.SkullIcon = skullIcon

    -- Chat Icon, display if need to talk to NPC
    local chatIcon = icon:CreateTexture(nil, 'BORDER', nil, 1)
    chatIcon:SetSize(iconSize + 4, iconSize + 4)
    chatIcon:SetPoint('TOPLEFT', icon, 'TOPLEFT')
    chatIcon:SetTexture([[Interface\WorldMap\ChatBubble_64.PNG]])
    chatIcon:SetTexCoord(0, 0.5, 0.5, 1)
    chatIcon:Hide()
    icon.ChatIcon = chatIcon

    local iconText = icon:CreateFontString(nil, 'OVERLAY')
    iconText:SetPoint('BOTTOMRIGHT', icon, 2, -0.8)
    iconText:SetFont(LSM:Fetch("font", self.db.font), self.db.fontSize,
                     self.db.fontOutline)
    icon.Text = iconText

    frame.QuestIcon[index] = icon
    return icon
end

function mod:UpdateElement_QuestIcon(frame)
    if self.db.questIcon ~= true then return end

    local questIcon = frame.QuestIcon

    for i = 1, #questIcon do questIcon[i]:Hide() end
    local QuestList = self:GetQuests(frame.unit)
    if not QuestList then return end

    local icon, objectiveCount, questType, itemTexture
    for i = 1, #QuestList do
        icon = self:Get_QuestIcon(frame, i)
        local quest = QuestList[i]
        local objectiveCount = quest.objectiveCount
        local itemTexture = quest.itemTexture
        local questType = quest.questType
        local isPerc = quest.isPerc

        if objectiveCount and (objectiveCount > 0 or isPerc) then
            icon.Text:SetText((isPerc and objectiveCount .. "%") or
                                  objectiveCount)

            icon.SkullIcon:Hide()
            icon.LootIcon:Hide()
            icon.ItemTexture:Hide()
            icon.ChatIcon:Hide()

            if questType == "KILL" or isPerc then
                icon.SkullIcon:Show()
            elseif questType == "LOOT" then
                icon.LootIcon:Show()
            elseif questType == "CHAT" then
                icon.ChatIcon:Show()
                icon.Text:SetText('')
            elseif questType == "QUEST_ITEM" then
                icon.ItemTexture:Show()
                icon.ItemTexture:SetTexture(itemTexture)
            end

            icon:Show()
        else
            icon:Hide()
        end
    end
end

function mod:QuestIcon_RelativePosition(frame, element)
    if not frame.QuestIcon then return end

    local unit, isCastbarLeft, isCastbarRight, isEliteLeft, isEliteRight =
        frame.UnitType, false, false, false, false
    if unit then
        if self.db.units[unit].castbar.enable and element == "Castbar" and
            self.db.units[unit].castbar.iconPosition == "RIGHT" then
            if frame.CastBar:IsShown() then isCastbarLeft = true end
        end

        if self.db.units[unit].eliteIcon and
            self.db.units[unit].eliteIcon.enable and
            self.db.units[unit].eliteIcon.position == "RIGHT" then
            if frame.Elite:IsShown() then isEliteLeft = true end
        end

        if self.db.units[unit].castbar.enable and element == "Castbar" and
            self.db.units[unit].castbar.iconPosition == "LEFT" then
            if frame.CastBar:IsShown() then isCastbarRight = true end
        end

        if self.db.units[unit].eliteIcon and
            self.db.units[unit].eliteIcon.enable and
            self.db.units[unit].eliteIcon.position == "LEFT" then
            if frame.Elite:IsShown() then isEliteRight = true end
        end
    end

    frame.QuestIcon:ClearAllPoints()
    if self.db.questIconPosition == "RIGHT" then
        if isCastbarLeft then
            frame.QuestIcon:SetPoint("LEFT", frame.CastBar.Icon, "RIGHT",
                                     self.db.questIconXOffset,
                                     self.db.questIconYOffset)
        elseif not isCastbarLeft and isEliteLeft then
            frame.QuestIcon:SetPoint("LEFT", frame.Elite, "RIGHT",
                                     self.db.questIconXOffset,
                                     self.db.questIconYOffset)
        else
            frame.QuestIcon:SetPoint("LEFT", frame.HealthBar, "RIGHT",
                                     self.db.questIconXOffset,
                                     self.db.questIconYOffset)
        end
    elseif self.db.questIconPosition == "LEFT" then
        if isCastbarRight then
            frame.QuestIcon:SetPoint("RIGHT", frame.CastBar.Icon, "LEFT",
                                     -(self.db.questIconXOffset),
                                     self.db.questIconYOffset)
        elseif not isCastbarRight and isEliteRight then
            frame.QuestIcon:SetPoint("RIGHT", frame.Elite, "LEFT",
                                     -(self.db.questIconXOffset),
                                     self.db.questIconYOffset)
        else
            frame.QuestIcon:SetPoint("RIGHT", frame.HealthBar, "LEFT",
                                     -(self.db.questIconXOffset),
                                     self.db.questIconYOffset)
        end
    end
end

function mod:ConfigureElement_QuestIcon(frame)
    local QuestList = self:GetQuests(frame.unit)
    if not QuestList then return end

    local iconSize = self.db.questIconSize
    local biggerIcon = iconSize + 4

    local icon
    for i = 1, #QuestList do
        icon = self:Get_QuestIcon(frame, i)
        icon:SetSize(iconSize, iconSize)
        icon.ItemTexture:SetSize(iconSize, iconSize)
        icon.LootIcon:SetSize(iconSize, iconSize)
        icon.SkullIcon:SetSize(iconSize, iconSize)
        icon.ChatIcon:SetSize(biggerIcon, biggerIcon)
    end
end

function mod:ConstructElement_QuestIcons(frame)
    local questIcons = CreateFrame("frame", nil, frame)
    questIcons:SetPoint("RIGHT", frame.HealthBar, "LEFT",
                        -(self.db.questIconXOffset), self.db.questIconYOffset)
    questIcons:SetSize(16, 16)
    return questIcons
end
