local addonName, addonTable = ...
---@type MKA
local MKA = addonTable.MKA
local core = addonTable
local TRANSLATE = core.TRANSLATE or function(msg) return msg end

local ACCOUNT_TYPE_PENDING_SPINNER_SIZE = 18

local function StopGroupAccountTypePendingAnimation(accountTypeContainer)
    if not accountTypeContainer then
        return
    end

    local spinner = accountTypeContainer.mkaAccountTypePendingSpinner
    if spinner then
        if spinner.Anim and spinner.Anim.Stop then
            spinner.Anim:Stop()
        end
        spinner:Hide()
    end
end

local function CreateFallbackGroupAccountTypeSpinner(parent)
    if not (CreateFrame and parent) then
        return nil
    end

    local spinner = CreateFrame("Frame", nil, parent)
    spinner.Ring = spinner:CreateTexture(nil, "ARTWORK")
    spinner.Ring:SetAllPoints(spinner)
    spinner.Ring:SetAtlas("Spinner_Ring")
    spinner.Sparks = spinner:CreateTexture(nil, "ARTWORK")
    spinner.Sparks:SetAllPoints(spinner)
    spinner.Sparks:SetAtlas("Spinner_Sparks")
    if spinner.Sparks.SetBlendMode then
        spinner.Sparks:SetBlendMode("ADD")
    end

    return spinner
end

local function GetGroupAccountTypePendingSpinner(accountTypeContainer)
    if not (accountTypeContainer and CreateFrame) then
        return nil
    end

    local spinner = accountTypeContainer.mkaAccountTypePendingSpinner
    if spinner then
        return spinner
    end

    local ok, nativeSpinner = pcall(CreateFrame, "Frame", nil, accountTypeContainer, "SpinnerTemplate")
    spinner = ok and nativeSpinner or CreateFallbackGroupAccountTypeSpinner(accountTypeContainer)
    if not spinner then
        return nil
    end

    if spinner.SetFrameLevel and accountTypeContainer.GetFrameLevel then
        spinner:SetFrameLevel((accountTypeContainer:GetFrameLevel() or 0) + 2)
    end
    spinner:Hide()
    accountTypeContainer.mkaAccountTypePendingSpinner = spinner
    return spinner
end

local function StartGroupAccountTypePendingAnimation(accountTypeContainer, accountTypeLabel, align, insetX, centerLabel)
    local spinner = GetGroupAccountTypePendingSpinner(accountTypeContainer)
    if not spinner then
        if accountTypeLabel then
            accountTypeLabel:SetText("")
        end
        return false
    end

    if accountTypeLabel then
        accountTypeLabel:SetText("")
    end

    insetX = tonumber(insetX) or 0
    spinner:ClearAllPoints()
    spinner:SetSize(ACCOUNT_TYPE_PENDING_SPINNER_SIZE, ACCOUNT_TYPE_PENDING_SPINNER_SIZE)
    if align == "LEFT" and centerLabel ~= true then
        spinner:SetPoint("LEFT", accountTypeContainer, "LEFT", insetX, 0)
    else
        spinner:SetPoint("CENTER", accountTypeContainer, "CENTER", 0, 0)
    end
    spinner:Show()
    if spinner.Anim and spinner.Anim.Play and (not spinner.Anim.IsPlaying or not spinner.Anim:IsPlaying()) then
        spinner.Anim:Play()
    end
    return true
end

local function HideGroupAccountTypeIconSlot(accountTypeContainer)
    local iconSlot = accountTypeContainer and accountTypeContainer.mkaAccountTypeIconSlot
    if iconSlot then
        iconSlot:Hide()
    end
end

local function HideGroupAccountTypeExtraIcons(accountTypeContainer)
    local extraIcons = accountTypeContainer and accountTypeContainer.mkaAccountTypeExtraIcons
    if type(extraIcons) ~= "table" then
        return
    end

    for _, icon in ipairs(extraIcons) do
        icon:Hide()
    end
end

local function GetGroupAccountTypeIconSlot(accountTypeContainer, iconSlotSize, align, insetX)
    local iconSlot = accountTypeContainer and accountTypeContainer.mkaAccountTypeIconSlot
    iconSlotSize = tonumber(iconSlotSize)
    if not (iconSlot and iconSlotSize and iconSlotSize > 0) then
        return nil
    end

    insetX = tonumber(insetX) or 0
    iconSlot:ClearAllPoints()
    iconSlot:SetSize(iconSlotSize, iconSlotSize)
    if align == "LEFT" then
        iconSlot:SetPoint("LEFT", accountTypeContainer, "LEFT", insetX, 0)
    else
        iconSlot:SetPoint("CENTER", accountTypeContainer, "CENTER", 0, 0)
    end
    iconSlot:Show()
    return iconSlot
end

local function SetGroupAccountTypeText(accountTypeIcon, accountTypeLabel, accountTypeContainer, text, textColor, align, insetX, centerLabel, pendingAnimation)
    if accountTypeIcon then
        accountTypeIcon:Hide()
    end
    HideGroupAccountTypeIconSlot(accountTypeContainer)
    HideGroupAccountTypeExtraIcons(accountTypeContainer)
    if not accountTypeLabel then
        return false
    end

    textColor = textColor or { 0.58, 0.58, 0.58, 1 }
    local containerWidth = (accountTypeContainer and accountTypeContainer.GetWidth and accountTypeContainer:GetWidth()) or core.GROUP_LIST_COLUMN_WIDTHS.accountType or 120
    insetX = tonumber(insetX) or 0

    accountTypeLabel:ClearAllPoints()
    if align == "LEFT" and centerLabel ~= true then
        accountTypeLabel:SetPoint("LEFT", accountTypeContainer, "LEFT", insetX, 0)
        accountTypeLabel:SetJustifyH("LEFT")
        accountTypeLabel:SetWidth(math.max(1, containerWidth - insetX))
    else
        accountTypeLabel:SetPoint("CENTER", accountTypeContainer, "CENTER", 0, 0)
        accountTypeLabel:SetJustifyH("CENTER")
        accountTypeLabel:SetWidth(containerWidth)
    end
    accountTypeLabel:SetHeight(18)
    accountTypeLabel:SetTextColor(textColor[1] or 0.58, textColor[2] or 0.58, textColor[3] or 0.58, textColor[4] or 1)
    if pendingAnimation == true then
        StartGroupAccountTypePendingAnimation(accountTypeContainer, accountTypeLabel, align, insetX, centerLabel)
    else
        StopGroupAccountTypePendingAnimation(accountTypeContainer)
        accountTypeLabel:SetText(text or "")
    end
    return true
end

local function SetGroupAccountTypeIconText(accountTypeIcon, accountTypeLabel, accountTypeContainer, texture, text, textColor, iconSize, iconGap, align, insetX, iconSlotSize, centerLabel)
    if not accountTypeIcon or not accountTypeLabel then
        return false
    end

    HideGroupAccountTypeExtraIcons(accountTypeContainer)
    StopGroupAccountTypePendingAnimation(accountTypeContainer)
    iconSize = iconSize or 16
    iconGap = iconGap or 3
    insetX = tonumber(insetX) or 0
    textColor = textColor or { 1, 0.82, 0, 1 }

    accountTypeIcon:SetTexture(texture)
    accountTypeIcon:SetTexCoord(0, 1, 0, 1)
    accountTypeIcon:SetSize(iconSize, iconSize)

    local containerWidth = (accountTypeContainer and accountTypeContainer.GetWidth and accountTypeContainer:GetWidth()) or core.GROUP_LIST_COLUMN_WIDTHS.accountType or 120
    local effectiveIconWidth = tonumber(iconSlotSize) or iconSize
    local centeredReserveWidth = 0
    if centerLabel == true and accountTypeContainer and accountTypeContainer.mkaAccountTypeReserveCenteredLabelIconSpace == true then
        centeredReserveWidth = math.max(0, effectiveIconWidth + iconGap + insetX)
    end
    local maxLabelWidth = centerLabel == true
        and math.max(1, containerWidth - centeredReserveWidth * 2)
        or math.max(1, containerWidth - effectiveIconWidth - iconGap - insetX)

    accountTypeLabel:ClearAllPoints()
    accountTypeLabel:SetWidth(maxLabelWidth)
    accountTypeLabel:SetText(text or "")
    accountTypeLabel:SetTextColor(textColor[1] or 1, textColor[2] or 0.82, textColor[3] or 0, textColor[4] or 1)
    accountTypeLabel:SetJustifyH(centerLabel == true and "CENTER" or "LEFT")
    accountTypeLabel:SetHeight(18)

    local labelWidth = centerLabel == true and maxLabelWidth or math.min(accountTypeLabel:GetStringWidth() or 28, maxLabelWidth)
    accountTypeLabel:SetWidth(labelWidth)

    local totalWidth = effectiveIconWidth + iconGap + labelWidth
    local iconSlot = GetGroupAccountTypeIconSlot(accountTypeContainer, iconSlotSize, align, insetX)
    accountTypeIcon:ClearAllPoints()
    if iconSlot then
        accountTypeIcon:SetPoint("CENTER", iconSlot, "CENTER", 0, 0)
    elseif align == "LEFT" then
        accountTypeIcon:SetPoint("LEFT", accountTypeContainer, "LEFT", insetX, 0)
    else
        accountTypeIcon:SetPoint("LEFT", accountTypeContainer, "CENTER", -totalWidth / 2, 0)
    end
    accountTypeLabel:ClearAllPoints()
    if centerLabel == true then
        accountTypeLabel:SetPoint("CENTER", accountTypeContainer, "CENTER", 0, 0)
    else
        accountTypeLabel:SetPoint("LEFT", iconSlot or accountTypeIcon, "RIGHT", iconGap, 0)
    end
    accountTypeIcon:Show()
    return true
end

local function GetGroupAccountTypeDisplayText(accountTypeInfo, character)
    local text = accountTypeInfo and accountTypeInfo.text
    if
        character
        and (character.mkaCompactMeetingStoneAccountTypeText == true or character.mkaCompactLeaderAccountTypeText == true)
        and type(text) == "string"
    then
        local compactText = accountTypeInfo.compactText or text:gsub("^火车头%s*", ""):gsub("^大秘%s*", "")
        if compactText ~= "" then
            return compactText
        end
    end

    return text
end

local function GetGroupAccountTypeKey(accountTypeInfo)
    if not accountTypeInfo then
        return nil
    end

    if type(accountTypeInfo.badges) == "table" then
        for _, badge in ipairs(accountTypeInfo.badges) do
            if badge and badge.key == "leaver" then
                return "leaver"
            end
        end
        for _, badge in ipairs(accountTypeInfo.badges) do
            if badge and badge.key == "newbie" then
                return "newbie"
            end
        end
        for _, badge in ipairs(accountTypeInfo.badges) do
            if badge and badge.key == "leader" then
                return "leader"
            end
        end
        for _, badge in ipairs(accountTypeInfo.badges) do
            if badge and badge.key == "star" then
                return "star"
            end
        end
        for _, badge in ipairs(accountTypeInfo.badges) do
            if badge and badge.key == "veteran" then
                return "veteran"
            end
        end
    end

    if accountTypeInfo.status == "leaver" then
        return "leaver"
    end
    if accountTypeInfo.status == "newbie" then
        return "newbie"
    end
    if accountTypeInfo.status == "leader" then
        return "leader"
    end
    if accountTypeInfo.status == "star" then
        return "star"
    end
    if accountTypeInfo.status == "veteran" then
        return "veteran"
    end

    return nil
end

local function GetGroupAccountTypeIconSizeOverride(character, accountTypeKey)
    if type(character) ~= "table" then
        return nil
    end

    local iconSizes = character.mkaAccountTypeIconSizes
    if type(iconSizes) == "table" and accountTypeKey then
        local iconSize = iconSizes[accountTypeKey]
        if type(iconSize) == "number" then
            return iconSize
        end
    end

    return character.mkaAccountTypeIconSize
end

function MKA:SetGroupAccountTypeIcon(row, characterEntry)
    if not row or not row.widgets or not row.widgets.accountTypeIcon then
        return
    end

    local accountTypeIcon = row.widgets.accountTypeIcon
    local accountTypeLabel = row.widgets.accountTypeLabel
    local accountTypeContainer = row.widgets.accountTypeContainer
    StopGroupAccountTypePendingAnimation(accountTypeContainer)
    accountTypeIcon:Hide()
    accountTypeIcon:ClearAllPoints()
    accountTypeIcon:SetPoint("CENTER", accountTypeContainer or row, "CENTER", 0, 0)
    HideGroupAccountTypeIconSlot(accountTypeContainer)
    HideGroupAccountTypeExtraIcons(accountTypeContainer)

    if accountTypeLabel then
        accountTypeLabel:ClearAllPoints()
        accountTypeLabel:SetPoint("CENTER", accountTypeContainer or row, "CENTER", 0, 0)
        accountTypeLabel:SetWidth((accountTypeContainer and accountTypeContainer.GetWidth and accountTypeContainer:GetWidth()) or 1)
        accountTypeLabel:SetHeight(18)
        accountTypeLabel:SetJustifyH("CENTER")
        accountTypeLabel:SetTextColor(1, 1, 1, 1)
        accountTypeLabel:SetText("")
    end

    local character = characterEntry and characterEntry.data or nil
    if type(character) ~= "table" then
        return
    end
    local accountTypeAlign = character.mkaAccountTypeAlign or (accountTypeContainer and accountTypeContainer.mkaAccountTypeAlign)
    local accountTypeInsetX = character.mkaAccountTypeInsetX
    if accountTypeInsetX == nil and accountTypeContainer then
        accountTypeInsetX = accountTypeContainer.mkaAccountTypeInsetX
    end
    local accountTypeIconSlotSize = character.mkaAccountTypeIconSlotSize or (accountTypeContainer and accountTypeContainer.mkaAccountTypeIconSlotSize)
    local accountTypeCenterLabel = character.mkaAccountTypeCenterLabel
    if accountTypeCenterLabel == nil and accountTypeContainer then
        accountTypeCenterLabel = accountTypeContainer.mkaAccountTypeCenterLabel
    end
    accountTypeCenterLabel = accountTypeCenterLabel == true

    if characterEntry.isOffline == true or character.isOffline == true then
        SetGroupAccountTypeText(
            accountTypeIcon,
            accountTypeLabel,
            accountTypeContainer or row,
            TRANSLATE(core.GROUP_LIST_ACCOUNT_TYPE_OFFLINE_TEXT or "STATUS.OFFLINE"),
            core.GROUP_LIST_ACCOUNT_TYPE_OFFLINE_TEXT_COLOR or { 0.52, 0.52, 0.52, 1 },
            accountTypeAlign,
            accountTypeInsetX,
            accountTypeCenterLabel
        )
        return
    end

    local name = character.name or characterEntry.key
    local realm = character.realm
    if type(name) == "string" and name:find("-", 1, true) and (type(realm) ~= "string" or realm == "") then
        local shortName, fullRealm = strsplit("-", name)
        name = shortName or name
        realm = fullRealm
    end

    local meetingStoneData = core.MeetingStoneData
    if meetingStoneData and meetingStoneData.QueryLeader then
        meetingStoneData:QueryLeader(name, realm)
    end

    local accountTypeInfo = meetingStoneData and meetingStoneData.GetAccountTypeInfo and meetingStoneData:GetAccountTypeInfo(name, realm) or nil
    if not accountTypeInfo or accountTypeInfo.status == "unknown" then
        return
    end
    if accountTypeInfo.status == "pending" then
        SetGroupAccountTypeText(
            accountTypeIcon,
            accountTypeLabel,
            accountTypeContainer or row,
            accountTypeInfo.text,
            accountTypeInfo.textColor,
            accountTypeAlign,
            accountTypeInsetX,
            accountTypeCenterLabel,
            true
        )
        return
    end
    local accountTypeKey = GetGroupAccountTypeKey(accountTypeInfo)
    local accountTypeIconSizeOverride = GetGroupAccountTypeIconSizeOverride(character, accountTypeKey)

    if not accountTypeInfo.texture then
        return
    end

    local displayText = GetGroupAccountTypeDisplayText(accountTypeInfo, character)
    SetGroupAccountTypeIconText(
        accountTypeIcon,
        accountTypeLabel,
        accountTypeContainer or row,
        accountTypeInfo.texture,
        displayText,
        accountTypeInfo.textColor,
        accountTypeIconSizeOverride or accountTypeInfo.width or 16,
        accountTypeInfo.gap or core.GROUP_LIST_ACCOUNT_TYPE_VETERAN_GAP or 3,
        accountTypeAlign,
        accountTypeInsetX,
        accountTypeIconSlotSize,
        accountTypeCenterLabel
    )
end
