local _, WN = ...

-- Gear Advisor 3.0
-- WoW AddOns cannot fetch live web pages. Live external sources are therefore
-- exposed as copyable links, while KeystoneLoot data is consumed through its
-- documented public in-game API when the addon is installed and loaded.

local specSlugs = {
    [62]="arcane", [63]="fire", [64]="frost",
    [65]="holy", [66]="protection", [70]="retribution",
    [71]="arms", [72]="fury", [73]="protection",
    [102]="balance", [103]="feral", [104]="guardian", [105]="restoration",
    [250]="blood", [251]="frost", [252]="unholy",
    [253]="beast-mastery", [254]="marksmanship", [255]="survival",
    [256]="discipline", [257]="holy", [258]="shadow",
    [259]="assassination", [260]="outlaw", [261]="subtlety",
    [262]="elemental", [263]="enhancement", [264]="restoration",
    [265]="affliction", [266]="demonology", [267]="destruction",
    [268]="brewmaster", [269]="windwalker", [270]="mistweaver",
    [577]="havoc", [581]="vengeance",
    [1467]="devastation", [1468]="preservation", [1473]="augmentation",
}

local classSlugs = {
    WARRIOR="warrior", PALADIN="paladin", HUNTER="hunter", ROGUE="rogue",
    PRIEST="priest", DEATHKNIGHT="death-knight", SHAMAN="shaman", MAGE="mage",
    WARLOCK="warlock", MONK="monk", DRUID="druid", DEMONHUNTER="demon-hunter", EVOKER="evoker",
}

local tierWeight = { [3]=500, [2]=400, [1]=300, [5]=200, [4]=100 }
local tierFallback = { [1]="Nice to have", [2]="Must have", [3]="Best in Slot", [4]="Transmog", [5]="Catalyst" }

-- Verified Archon snapshot for Windwalker Mythic+ on 23 Aug 2026.
-- Data source URL is generated below and shown inside the UI.
WN.gearAdvisorSnapshots = {
    -- Protection Paladin: Archon M+ meta snapshot plus Wowhead BiS guide, checked 23 Aug 2026.
    [66] = {
        date = "23.08.2026",
        content = "Mythisch+ High Keys",
        sample = "3.289 Parses, Top 5%, letzte 14 Tage",
        statPriority = "Tempo = Krit > Meisterschaft > Vielseitigkeit",
        enchants = {
            {slot="Kopf", name="Empowered Hex of Leeching", popularity="45.7%"},
            {slot="Schultern", name="Silvermoon's Mending", popularity="43.2%"},
            {slot="Brust", name="Mark of the Worldsoul", popularity="67.3%"},
            {slot="Beine", name="Forest Hunter's Armor Kit", popularity="71.6%"},
            {slot="Füße", name="Shaladrassil's Roots", popularity="37.2%"},
            {slot="Ringe", name="Eyes of the Eagle", popularity="41.4%"},
            {slot="Waffenhand", name="Acuity of the Ren'dorei", popularity="57.6%"},
        },
        gems = {
            {kind="Epischer Sockel", name="Indecipherable Eversong Diamond", stats="Stärke", popularity="59.4%"},
            {kind="Standard Sockel", name="Flawless Quick Garnet", stats="Krit / Tempo", popularity="35.1%"},
            {kind="Alternative", name="Flawless Deadly Peridot", stats="Tempo / Krit", popularity="33.5%"},
        },
        bis = {
            [16]={itemId=268209, source="The Coiled Altar"},
            [17]={itemId=268196, source="The Lost Explorers"},
            [1]={itemId=271465, source="Tier Set"},
            [2]={itemId=268265, source="Ula'tek"},
            [3]={itemId=271463, source="Tier Set"},
            [15]={itemId=268253, source="The Coiled Altar"},
            [5]={itemId=271468, source="Tier Set"},
            [9]={itemId=237834, source="Crafting: Blacksmithing"},
            [10]={itemId=271466, source="Tier Set"},
            [6]={itemId=268259, source="The Coiled Altar"},
            [7]={itemId=271878, source="Ula'tek"},
            [8]={itemId=237828, source="Crafting: Blacksmithing"},
            [11]={itemId=268252, source="Sszorak"},
            [12]={itemId=268249, source="Vashnik the Malignant"},
            [13]={itemId=270173, source="The Coiled Altar"},
            [14]={itemId=270175, source="Ula'tek"},
        },
        bisDate = "12.08.2026",
    },
    [269] = {
        date = "23.08.2026",
        content = "Mythisch+",
        sample = "30.173 Parses, +7 bis +19",
        statPriority = "Beweglichkeit > Tempo > Krit > Meisterschaft > Vielseitigkeit",
        enchants = {
            {slot="Kopf", name="Empowered Rune of Avoidance", popularity="43.4%"},
            {slot="Schultern", name="Amirdrassil's Grace", popularity="45.9%"},
            {slot="Brust", name="Mark of the Worldsoul", popularity="75.8%"},
            {slot="Beine", name="Forest Hunter's Armor Kit", popularity="73.8%"},
            {slot="Füße", name="Lynx's Dexterity", popularity="46.6%"},
            {slot="Ringe", name="Eyes of the Eagle", popularity="65.4%"},
            {slot="Waffe", name="Acuity of the Ren'dorei", popularity="60.7%"},
        },
        gems = {
            {kind="Epischer Sockel", name="Indecipherable Eversong Diamond", stats="Beweglichkeit", popularity="68.4%"},
            {kind="Standard Sockel", name="Flawless Deadly Peridot", stats="Tempo / Krit", popularity="47.0%"},
            {kind="Alternative", name="Flawless Masterful Peridot", stats="Tempo / Meisterschaft", popularity="28.6%"},
        },
    },
}

function WN:GetActiveSpecIdentity()
    local specIndex = type(GetSpecialization)=="function" and self:SafeNumber(self:SafeCall(GetSpecialization), nil) or nil
    local specID, specName, _, specIcon, role
    if specIndex and type(GetSpecializationInfo)=="function" then
        specID, specName, _, specIcon, role = self:SafeCall(GetSpecializationInfo, specIndex)
    end
    local _, classFile = UnitClass("player")
    return {
        specID=self:SafeNumber(specID,0) or 0,
        specName=self:SafeString(specName,""),
        specIcon=specIcon,
        role=self:SafeString(role,""),
        classFile=classFile,
        classSlug=classSlugs[classFile],
        specSlug=specSlugs[self:SafeNumber(specID,0) or 0],
    }
end

function WN:GetArchonAdvisorURLs()
    local s = self:GetActiveSpecIdentity()
    if not s.classSlug or not s.specSlug then return nil end
    local root = "https://www.archon.gg/wow/builds/"..s.specSlug.."/"..s.classSlug.."/mythic-plus/"
    return {
        enchants=root.."enchants-and-gems/10/all-dungeons/this-week",
        gear=root.."gear-and-tier-set/10/all-dungeons/this-week",
        overview=root.."overview/10/all-dungeons/this-week",
    }
end

function WN:ShowCopyLink(title, value)
    if not self.linkDialog then
        local f=CreateFrame("Frame","WoWNextLinkDialog",UIParent,"BackdropTemplate")
        f:SetSize(620,150); f:SetPoint("CENTER"); f:SetFrameStrata("DIALOG"); f:SetClampedToScreen(true)
        self.ApplyBackdrop(f,self.colors.bgDeep,self.colors.accentDim)
        f.title=self:CreateText(f,14,self.colors.text,"LEFT"); f.title:SetPoint("TOPLEFT",18,-18)
        f.help=self:CreateText(f,9,self.colors.muted,"LEFT"); f.help:SetPoint("TOPLEFT",18,-43); f.help:SetText(self:T("COPY_LINK_HELP"))
        f.edit=CreateFrame("EditBox",nil,f,"InputBoxTemplate"); f.edit:SetPoint("TOPLEFT",18,-72); f.edit:SetPoint("TOPRIGHT",-18,-72); f.edit:SetHeight(30); f.edit:SetAutoFocus(false); f.edit:SetMaxLetters(2048)
        f.edit:SetScript("OnEscapePressed",function(e) e:ClearFocus(); f:Hide() end)
        f.close=self:CreateButton(f,90,28,self:T("CLOSE"),function() f.edit:ClearFocus(); f:Hide() end); f.close:SetPoint("BOTTOMRIGHT",-18,14)
        self.linkDialog=f
    end
    local f=self.linkDialog; f.title:SetText(title or self:T("LINK")); f.edit:SetText(value or ""); f:Show(); f.edit:SetFocus(); f.edit:HighlightText()
end

function WN:GetEnhancementAdvisor()
    local s=self:GetActiveSpecIdentity()
    local snapshot=self.gearAdvisorSnapshots and self.gearAdvisorSnapshots[s.specID] or nil
    return { spec=s, snapshot=snapshot, urls=self:GetArchonAdvisorURLs() }
end

local function GetItemDisplay(itemID)
    local name, icon
    if C_Item and type(C_Item.RequestLoadItemDataByID)=="function" then pcall(C_Item.RequestLoadItemDataByID,itemID) end
    if C_Item and type(C_Item.GetItemNameByID)=="function" then name=WN:SafeString(WN:SafeCall(C_Item.GetItemNameByID,itemID),nil) end
    if C_Item and type(C_Item.GetItemIconByID)=="function" then icon=WN:SafeCall(C_Item.GetItemIconByID,itemID) end
    if not name and type(GetItemInfo)=="function" then local n,_,_,_,_,_,_,_,_,i=WN:SafeCall(GetItemInfo,itemID); name=WN:SafeString(n,nil); icon=icon or i end
    return name or ("Item "..tostring(itemID)), icon
end

function WN:GetKeystoneLootAdvisor(limit)
    limit=limit or 8
    local api=_G.KeystoneLootAPI
    local spec=self:GetActiveSpecIdentity()
    local result={available=type(api)=="table", specID=spec.specID, entries={}, message=nil}
    if not result.available then result.message=self:T("KEYSTONELOOT_NOT_LOADED"); return result end
    if type(api.GetFavoritesBySpec)~="function" then result.message=self:T("KEYSTONELOOT_API_INCOMPATIBLE"); return result end
    local ok, favorites=pcall(api.GetFavoritesBySpec,api,spec.specID)
    if not ok or type(favorites)~="table" then result.message=self:T("KEYSTONELOOT_NO_DATA"); return result end
    for _,entry in ipairs(favorites) do
        if type(entry)=="table" and entry.itemId then
            local name,icon=GetItemDisplay(entry.itemId)
            local sourceName=self:T("UNKNOWN_SOURCE"); local sourceType=""; local sourceID=entry.sourceId
            if not sourceID and type(api.GetItemSource)=="function" then
                local okItemSource,itemSource=pcall(api.GetItemSource,api,entry.itemId)
                if okItemSource then
                    if type(itemSource)=="table" then sourceName=itemSource.name or itemSource.title or sourceName; sourceType=itemSource.type or ""; sourceID=itemSource.id or itemSource.sourceId
                    elseif type(itemSource)=="number" then sourceID=itemSource
                    elseif type(itemSource)=="string" then sourceName=itemSource end
                end
            end
            if type(api.GetSourceInfo)=="function" and sourceID~=nil then
                local okSource,source=pcall(api.GetSourceInfo,api,sourceID)
                if okSource and type(source)=="table" then sourceName=source.name or source.title or sourceName; sourceType=source.type or sourceType end
            end
            result.entries[#result.entries+1]={
                itemId=entry.itemId, name=name, icon=icon, source=sourceName, sourceType=sourceType,
                tier=tonumber(entry.tier) or 0, tierName=entry.tierName or self:T("LOOT_TIER_"..tostring(tonumber(entry.tier) or 0)) or tierFallback[tonumber(entry.tier) or 0] or self:T("FAVORITE"),
                enchant=entry.enchant, gems=entry.gems,
            }
        end
    end
    table.sort(result.entries,function(a,b)
        local aw=tierWeight[a.tier] or 0; local bw=tierWeight[b.tier] or 0
        if aw==bw then return tostring(a.name)<tostring(b.name) end
        return aw>bw
    end)
    while #result.entries>limit do table.remove(result.entries) end
    if #result.entries==0 then result.message=self:T("KEYSTONELOOT_EMPTY_SPEC") end
    return result
end

local equipLocBySlot = {
    [1]={INVTYPE_HEAD=true}, [2]={INVTYPE_NECK=true}, [3]={INVTYPE_SHOULDER=true}, [15]={INVTYPE_CLOAK=true},
    [5]={INVTYPE_CHEST=true,INVTYPE_ROBE=true}, [9]={INVTYPE_WRIST=true}, [10]={INVTYPE_HAND=true}, [6]={INVTYPE_WAIST=true},
    [7]={INVTYPE_LEGS=true}, [8]={INVTYPE_FEET=true}, [11]={INVTYPE_FINGER=true}, [12]={INVTYPE_FINGER=true},
    [13]={INVTYPE_TRINKET=true}, [14]={INVTYPE_TRINKET=true},
    [16]={INVTYPE_WEAPON=true,INVTYPE_2HWEAPON=true,INVTYPE_WEAPONMAINHAND=true,INVTYPE_RANGED=true,INVTYPE_RANGEDRIGHT=true},
    [17]={INVTYPE_SHIELD=true,INVTYPE_HOLDABLE=true,INVTYPE_WEAPONOFFHAND=true,INVTYPE_WEAPON=true},
}

local function ItemFitsSlot(itemID, slotID)
    if not itemID or not slotID or type(GetItemInfoInstant)~="function" then return false end
    local _,_,_,equipLoc = GetItemInfoInstant(itemID)
    return type(equipLoc)=="string" and equipLocBySlot[slotID] and equipLocBySlot[slotID][equipLoc] == true
end

local function LocalizeSource(source)
    if type(source)~="string" then return source end
    if WN.activeLocale=="deDE" or (WN.db and WN.db.settings and WN.db.settings.language=="deDE") then
        if source=="Tier Set" then return "Tier-Set" end
        if source=="Crafting: Blacksmithing" then return "Herstellung: Schmiedekunst" end
    end
    return source
end

function WN:GetBestInSlotForSlot(slotID)
    slotID=tonumber(slotID)
    if not slotID then return nil end

    -- First preference: the player's own/imported KeystoneLoot BiS list. This works for every spec.
    local api=_G.KeystoneLootAPI
    local spec=self:GetActiveSpecIdentity()
    if type(api)=="table" and type(api.GetFavoritesBySpec)=="function" and spec.specID and spec.specID>0 then
        local ok,favorites=pcall(api.GetFavoritesBySpec,api,spec.specID)
        if ok and type(favorites)=="table" then
            local candidates={}
            for _,entry in ipairs(favorites) do
                if type(entry)=="table" and entry.itemId and ItemFitsSlot(entry.itemId,slotID) then
                    local tier=tonumber(entry.tier) or 2
                    if tier==3 then
                        local sourceName=self:T("UNKNOWN_SOURCE")
                        local sourceID=entry.sourceId
                        if not sourceID and type(api.GetItemSource)=="function" then
                            local okSource,source=pcall(api.GetItemSource,api,entry.itemId)
                            if okSource then
                                if type(source)=="table" then sourceName=source.name or source.title or sourceName; sourceID=source.id or source.sourceId
                                elseif type(source)=="number" then sourceID=source
                                elseif type(source)=="string" then sourceName=source end
                            end
                        end
                        if sourceID and type(api.GetSourceInfo)=="function" then
                            local okInfo,info=pcall(api.GetSourceInfo,api,sourceID)
                            if okInfo and type(info)=="table" then sourceName=info.name or info.title or sourceName end
                        end
                        local name,icon=GetItemDisplay(entry.itemId)
                        candidates[#candidates+1]={itemId=entry.itemId,name=name,icon=icon,source=sourceName,tier=tier,provider="keystoneloot"}
                    end
                end
            end
            table.sort(candidates,function(a,b)
                local aw=tierWeight[a.tier] or 0; local bw=tierWeight[b.tier] or 0
                if aw==bw then return tostring(a.name)<tostring(b.name) end
                return aw>bw
            end)
            if #candidates>0 then
                local index=((slotID==12 or slotID==14) and #candidates>1) and 2 or 1
                return candidates[index] or candidates[1]
            end
        end
    end

    -- Fallback: verified bundled snapshot for specs where WoWNext has one.
    local snapshot=self.gearAdvisorSnapshots and self.gearAdvisorSnapshots[spec.specID]
    local entry=snapshot and snapshot.bis and snapshot.bis[slotID]
    if entry and entry.itemId then
        local name,icon=GetItemDisplay(entry.itemId)
        return {itemId=entry.itemId,name=name,icon=icon,source=LocalizeSource(entry.source),tier=3,provider="snapshot",date=snapshot.bisDate or snapshot.date}
    end
    return nil
end

function WN:AddBestInSlotToTooltip(tip,slotID,currentItemLink)
    if not tip or not slotID then return end
    local bis=self:GetBestInSlotForSlot(slotID)
    tip:AddLine(" ")
    tip:AddLine(self:T("BIS_TOOLTIP_TITLE"), self.colors.accent[1], self.colors.accent[2], self.colors.accent[3])
    if not bis then
        tip:AddLine(self:T("BIS_NO_DATA"),0.72,0.78,0.82,true)
        return
    end
    local currentID
    if currentItemLink and type(GetItemInfoInstant)=="function" then currentID=select(1,GetItemInfoInstant(currentItemLink)) end
    if bis.itemId then
        local link
        if C_Item and type(C_Item.GetItemLinkByID)=="function" then link=self:SafeCall(C_Item.GetItemLinkByID,bis.itemId) end
        if not link and type(GetItemInfo)=="function" then link=select(2,self:SafeCall(GetItemInfo,bis.itemId)) end
        tip:AddLine(link or bis.name or ("Item "..tostring(bis.itemId)),0.95,0.95,0.98,true)
    end
    if currentID and bis.itemId and tonumber(currentID)==tonumber(bis.itemId) then tip:AddLine("✓ "..self:T("BIS_ALREADY_EQUIPPED"),0.25,0.95,0.55) end
    local provider=bis.provider=="keystoneloot" and self:T("BIS_FROM_KEYSTONELOOT") or self:T("BIS_FROM_SNAPSHOT")
    local source=bis.source and bis.source~="" and (" • "..self:T("BIS_SOURCE")..": "..bis.source) or ""
    tip:AddLine(provider..source,0.58,0.70,0.76,true)
    if bis.date then tip:AddLine(self:T("DATA_SNAPSHOT")..": "..tostring(bis.date),0.45,0.55,0.60) end
    tip:AddLine(self:T("BIS_META_NOTE"),0.45,0.55,0.60,true)
end

function WN:GetGearActionList(data)
    data=data or self.cachedOverview or self:GetOverviewData()
    local e=data and data.equipment or {}; local actions={}
    for _,item in ipairs(e.items or {}) do
        if item.status=="missing" then actions[#actions+1]={priority=100,icon=self.icons.warning,title=item.slotName,meta=self:T("ITEM_MISSING"),value=self:T("ACTION_MISSING"),item=item} end
        if item.missingEnchant then actions[#actions+1]={priority=90,icon=item.icon,title=item.slotName,meta=self:T("MISSING_ENCHANT"),value=self:T("ACTION_ENCHANT"),item=item} end
        if (item.emptySockets or 0)>0 then actions[#actions+1]={priority=80,icon=item.icon,title=item.slotName,meta=self:T("EMPTY_SOCKET_COUNT",item.emptySockets),value=self:T("ACTION_SOCKET"),item=item} end
    end
    for _,item in ipairs(e.upgradeCandidates or {}) do actions[#actions+1]={priority=50,icon=item.icon,title=item.slotName,meta=item.name or "",value="iLvl "..tostring(math.floor((item.itemLevel or 0)+0.5)),item=item} end
    table.sort(actions,function(a,b) if a.priority==b.priority then return tostring(a.title)<tostring(b.title) end return a.priority>b.priority end)
    return actions
end
