local pluginName, pluginShared = ...
local L = LibStub("AceLocale-3.0"):GetLocale("AppearanceMatic")

-- Detection: which sibling Infinite Loop Alchemist addons are on this client. The Detection tab
-- shows each one's card with a switch that sits off until the addon is installed.
local Detection = {}
pluginShared.Detection = Detection

local SWITCH_ON = "Interface\\AddOns\\AppearanceMatic\\Media\\Textures\\route-toggle-on.tga"
local SWITCH_OFF = "Interface\\AddOns\\AppearanceMatic\\Media\\Textures\\route-toggle-off.tga"

local function addonLoaded(name)
    if type(C_AddOns) == "table" and type(C_AddOns.IsAddOnLoaded) == "function" then
        return C_AddOns.IsAddOnLoaded(name) and true or false
    end
    if type(IsAddOnLoaded) == "function" then
        return IsAddOnLoaded(name) and true or false
    end
    return false
end

local function addonVersion(name)
    local getter = (type(C_AddOns) == "table" and C_AddOns.GetAddOnMetadata) or GetAddOnMetadata
    if type(getter) ~= "function" then
        return nil
    end
    local ok, version = pcall(getter, name, "Version")
    return (ok and type(version) == "string" and version ~= "") and version or nil
end

function Detection:Installed(name)
    return addonLoaded(name)
end

function Detection:Version(name)
    return addonVersion(name)
end

-- the switch graphic for an addon: on when installed, off otherwise
function Detection:SwitchTexture(name)
    return self:Installed(name) and SWITCH_ON or SWITCH_OFF
end

function Detection:StatusText(name)
    if not self:Installed(name) then
        return L["detect_not_installed"]
    end
    if name == "GearMatic" and not self:GearMaticGuardHook() then
        return L["detect_needs_update"]
    end
    return string.format(L["detect_installed_fmt"], self:Version(name) or "?")
end

-- GearMatic: its vendor automation (gear auto-sell by legacy expansion or item level, auto repair)
-- and the keep guard AppearanceMatic hands it so uncollected appearances never get auto-sold.
local GUARD_NAME = "AppearanceMatic"

-- the sell-guard hook, present from the GearMatic version that can keep items for us
function Detection:GearMaticGuardHook()
    local gm = _G.GearMatic
    local vendor = type(gm) == "table" and gm.VendorAutomation or nil
    if type(vendor) == "table" and type(vendor.RegisterSellGuard) == "function" then
        return vendor
    end
    return nil
end

-- "missing", "hookless" (installed, too old to keep items), "installed"
function Detection:GearMaticState()
    if not self:Installed("GearMatic") then
        return "missing"
    end
    if not self:GearMaticGuardHook() then
        return "hookless"
    end
    return "installed"
end

-- What GearMatic's vendor automation is set to right now, from its own profile
function Detection:GearMaticAutomation()
    local gm = _G.GearMatic
    local profile = type(gm) == "table" and type(gm.db) == "table" and gm.db.profile or nil
    if type(profile) ~= "table" then
        return nil
    end
    local rule = profile.autoSellGearRule
    if rule ~= "ilvl" and rule ~= "expansion" and rule ~= "either" then
        rule = "ilvl"
    end
    return {
        sellGear = profile.autoSellGear == true,
        rule = rule,
        ilvl = tonumber(profile.autoSellGearIlvl) or 0,
        repair = profile.autoRepair ~= false,
    }
end

function Detection:AutoSellText()
    local auto = self:GearMaticAutomation()
    if not (auto and auto.sellGear) then
        return L["detect_autosell_off"]
    end
    if auto.rule == "expansion" then
        return L["detect_autosell_legacy"]
    elseif auto.rule == "either" then
        return string.format(L["detect_autosell_either_fmt"], auto.ilvl)
    end
    return string.format(L["detect_autosell_ilvl_fmt"], auto.ilvl)
end

function Detection:AutoRepairText()
    local auto = self:GearMaticAutomation()
    return (auto and auto.repair) and L["detect_autorepair_on"] or L["detect_autorepair_off"]
end

-- true when the item's appearance is not in the collection yet, so GearMatic keeps the item
function Detection:KeepUncollected(link)
    if type(link) ~= "string" or type(C_TransmogCollection) ~= "table" then
        return false
    end
    if type(C_TransmogCollection.GetItemInfo) ~= "function" or type(C_TransmogCollection.PlayerHasTransmogItemModifiedAppearance) ~= "function" then
        return false
    end
    local ok, _, sourceID = pcall(C_TransmogCollection.GetItemInfo, link)
    if not (ok and type(sourceID) == "number" and sourceID > 0) then
        return false
    end
    local okHas, has = pcall(C_TransmogCollection.PlayerHasTransmogItemModifiedAppearance, sourceID)
    if not okHas then
        return false
    end
    return not has
end

-- The guard is on whenever GearMatic can take it: nothing to switch
function Detection:AttachGuard()
    local vendor = self:GearMaticGuardHook()
    if not vendor then
        return false
    end
    vendor.RegisterSellGuard(GUARD_NAME, function(link) return Detection:KeepUncollected(link) end)
    return true
end

-- GearMatic loads after AppearanceMatic (alphabetical order): attach once it is in, and at login
if type(CreateFrame) == "function" then
    local watcher = CreateFrame("Frame")
    watcher:RegisterEvent("ADDON_LOADED")
    watcher:RegisterEvent("PLAYER_LOGIN")
    watcher:SetScript("OnEvent", function(_, event, name)
        if event == "ADDON_LOADED" and name ~= "GearMatic" then
            return
        end
        Detection:AttachGuard()
    end)
end
