local _, addonTable = ...
local core = addonTable
local TRANSLATE = core.TRANSLATE or function(msg) return msg end

core.GroupTab = core.GroupTab or {}
local GroupTab = core.GroupTab

local GROUP_LIST_HEADER_HEIGHT = core.GROUP_LIST_HEADER_HEIGHT or 36
local GROUP_LIST_ROWS_PADDING_X = core.GROUP_LIST_ROWS_PADDING_X or 4
local GROUP_LIST_ROW_HEIGHT = core.GROUP_LIST_ROW_HEIGHT or 36
local GROUP_REFRESH_BUTTON_SIZE = 24
local GROUP_REFRESH_BUTTON_ICON_SIZE = 16
local GROUP_REFRESH_BUTTON_ICON_PRESSED_SIZE = 15
local GROUP_REFRESH_BUTTON_INSET = 10
local GROUP_REFRESH_BUTTON_TEXTURE = "Interface\\AddOns\\MyKeyStone\\Art\\Ui\\Refresh.png"

local function SetGroupRefreshButtonIconPressed(button, pressed)
    local icon = button and button.Icon
    if not icon then
        return
    end

    icon:ClearAllPoints()
    if pressed then
        icon:SetSize(GROUP_REFRESH_BUTTON_ICON_PRESSED_SIZE, GROUP_REFRESH_BUTTON_ICON_PRESSED_SIZE)
        icon:SetPoint("CENTER", button, "CENTER", 1, -1)
        icon:SetAlpha(0.86)
    else
        icon:SetSize(GROUP_REFRESH_BUTTON_ICON_SIZE, GROUP_REFRESH_BUTTON_ICON_SIZE)
        icon:SetPoint("CENTER", button, "CENTER", 0, 0)
        icon:SetAlpha(1)
    end
end

local function SetGroupRefreshButtonArtPressed(button, pressed)
    if not button then
        return
    end

    button.mkMeetingStoneButtonPressed = pressed and true or nil
    if core.MeetingStoneButtonArt and core.MeetingStoneButtonArt.Update then
        core.MeetingStoneButtonArt.Update(button)
    end
end

local function ResetGroupRefreshScrollPosition(widgets)
    if widgets and widgets.groupScrollBox and widgets.groupScrollBox.ScrollToBegin then
        widgets.groupScrollBox:ScrollToBegin(ScrollBoxConstants and ScrollBoxConstants.NoScrollInterpolation)
        return
    end

    local scrollBar = widgets and widgets.groupScrollBar
    if scrollBar and scrollBar.mkSetScrollValue then
        scrollBar.mkSetScrollValue(0)
    elseif scrollBar and scrollBar.SetValue then
        scrollBar:SetValue(0)
    end
end

local function ResetGroupRefreshRatingState(owner)
    if not owner then
        return
    end

    owner.groupRatingLookupStartedAt = {}
    owner.groupRatingLookupRefreshTimers = {}
    owner.groupUnitRatingCache = {}
    owner.groupUnitRatingLookupDirty = nil
    owner.groupUnitRatingLookupQueue = {}
    owner.groupUnitRatingLookupPending = {}
end

local function RefreshGroupTabData(owner, widgets, listKind)
    if not owner then
        return
    end
    listKind = listKind == "carpool" and "carpool" or "group"
    local refreshSource = listKind == "carpool" and "CarpoolRefreshButton" or "GroupRefreshButton"

    if core.ResetGroupSortState then
        core.ResetGroupSortState(owner, listKind)
    end
    if core.UpdateGroupHeaderSortIndicators and widgets and widgets.groupHeaderFrame then
        core.UpdateGroupHeaderSortIndicators(owner, widgets.groupHeaderFrame)
    end
    if owner.lastRenderedSnapshotByTab then
        owner.lastRenderedSnapshotByTab[listKind] = nil
    end

    ResetGroupRefreshRatingState(owner)
    ResetGroupRefreshScrollPosition(widgets)

    if owner.RequestMythicPlusSystemData then
        owner:RequestMythicPlusSystemData(refreshSource)
    end
    if owner.ProcessCharacterUpdate then
        owner:ProcessCharacterUpdate(refreshSource)
    end
    if owner.QueueCharacterUpdate then
        owner:QueueCharacterUpdate(0.15, refreshSource)
    end
    if owner.QueueBroadcastUpdate then
        owner:QueueBroadcastUpdate(0.05)
    end
    if owner.QueueGroupSyncRequest then
        owner:QueueGroupSyncRequest(0.05)
    end
    if owner.RefreshMainWindow then
        owner:RefreshMainWindow(refreshSource)
    end
end

local function CreateGroupRefreshButton(owner, parent, widgets, listKind)
    listKind = listKind == "carpool" and "carpool" or "group"
    local titleText = listKind == "carpool" and "刷新车队列表" or "刷新队伍列表"
    local descriptionText = listKind == "carpool" and "恢复默认排序并刷新车队角色数据" or "恢复默认排序并刷新队伍角色数据"

    local button = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
    button:SetSize(GROUP_REFRESH_BUTTON_SIZE, GROUP_REFRESH_BUTTON_SIZE)
    button:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", -GROUP_REFRESH_BUTTON_INSET, GROUP_REFRESH_BUTTON_INSET)
    button:SetFrameLevel((parent:GetFrameLevel() or 0) + 8)
    button:RegisterForClicks("LeftButtonUp")
    button:SetText("")

    if core.MeetingStoneButtonArt and core.MeetingStoneButtonArt.Apply then
        core.MeetingStoneButtonArt.Apply(button)
    end

    local icon = button:CreateTexture(nil, "OVERLAY")
    icon:SetTexture(GROUP_REFRESH_BUTTON_TEXTURE)
    icon:SetTexCoord(0, 1, 0, 1)
    button.Icon = icon
    SetGroupRefreshButtonIconPressed(button, false)

    button:SetScript("OnClick", function()
        RefreshGroupTabData(owner, widgets, listKind)
    end)
    button:SetScript("OnEnter", function(hoveredButton)
        SetGroupRefreshButtonArtPressed(hoveredButton, false)
        GameTooltip:SetOwner(hoveredButton, "ANCHOR_LEFT")
        if GameTooltip_SetTitle then
            GameTooltip_SetTitle(GameTooltip, TRANSLATE(titleText))
        else
            GameTooltip:SetText(TRANSLATE(titleText), 1, 0.82, 0, true)
        end
        GameTooltip:AddLine(TRANSLATE(descriptionText), 1, 1, 1, true)
        GameTooltip:Show()
    end)
    button:SetScript("OnLeave", function(hoveredButton)
        SetGroupRefreshButtonIconPressed(hoveredButton, false)
        SetGroupRefreshButtonArtPressed(hoveredButton, false)
        if GameTooltip:GetOwner() == hoveredButton then
            GameTooltip:Hide()
        end
    end)
    button:SetScript("OnMouseDown", function(clickedButton, mouseButton)
        if mouseButton == "LeftButton" then
            SetGroupRefreshButtonIconPressed(clickedButton, true)
            SetGroupRefreshButtonArtPressed(clickedButton, true)
        end
    end)
    button:SetScript("OnMouseUp", function(clickedButton)
        SetGroupRefreshButtonIconPressed(clickedButton, false)
        SetGroupRefreshButtonArtPressed(clickedButton, false)
    end)

    return button
end

function GroupTab.BuildList(owner, tabGroup, options)
    options = options or {}

    local tabKey = options.tabKey or "group"
    local applyPanelStyle = core.ApplyGroupRowsFrameStyle
    local createFrameWithTemplates = core.CreateFrameWithTemplateOptions
    local createHeaderFrame = core.CreateGroupHeaderFrame
    local layoutGroupListPanel = core.LayoutGroupListPanel
    if not (applyPanelStyle and createFrameWithTemplates and createHeaderFrame and layoutGroupListPanel) then
        return
    end

    local groupPreviewFrame = CreateFrame("Frame", nil, UIParent)
    groupPreviewFrame:ClearAllPoints()
    tabGroup:AddChild(groupPreviewFrame)
    groupPreviewFrame:SetFrameLevel((tabGroup.frame and tabGroup.frame:GetFrameLevel() or 0) + 1)
    groupPreviewFrame:Hide()
    applyPanelStyle(groupPreviewFrame)

    local itemList = CreateFrame("Frame", nil, groupPreviewFrame)
    itemList:SetFrameLevel(groupPreviewFrame:GetFrameLevel() + 1)

    local groupOuterInsetX = 6
    local groupListTopInset = 18
    local groupListBottomInset = 12
    local groupHeaderRowGap = 6
    local groupScrollBarWidth = 17
    local groupScrollBarXOffset = 19
    local groupScrollBarTopInset = 2
    local groupScrollBarBottomInset = 2
    local groupBrowseLeftOffset = groupOuterInsetX
    local groupBrowseTopOffset = -groupListTopInset
    local groupBrowseRightOffset = -groupOuterInsetX
    local groupBrowseBottomOffset = groupListBottomInset
    local groupBrowseCenterList = options.centerList == true
    local groupBrowseMaxWidth = tonumber(options.listMaxWidth)
    if groupBrowseCenterList and not groupBrowseMaxWidth and core.GetGroupColumnLayout then
        local columnLayout = core.GetGroupColumnLayout(options.columnWidths or core.GROUP_LIST_COLUMN_WIDTHS)
        groupBrowseMaxWidth = (columnLayout.totalWidth or 0) + (GROUP_LIST_ROWS_PADDING_X * 2)
    end

    itemList:ClearAllPoints()
    itemList:SetPoint("TOPLEFT", groupPreviewFrame, "TOPLEFT", groupBrowseLeftOffset, groupBrowseTopOffset)
    itemList:SetPoint("BOTTOMRIGHT", groupPreviewFrame, "BOTTOMRIGHT", groupBrowseRightOffset, groupBrowseBottomOffset)
    if itemList.SetClipsChildren then
        itemList:SetClipsChildren(false)
    end

    local headerContainer = CreateFrame("Frame", nil, itemList)
    headerContainer:SetFrameLevel(itemList:GetFrameLevel() + 1)
    itemList.HeaderContainer = headerContainer

    local scrollBox, scrollBoxTemplate = createFrameWithTemplates("Frame", nil, itemList, {
        "WowScrollBoxList",
        "WoWScrollBoxList",
    })
    local scrollBar, scrollBarTemplate = createFrameWithTemplates("EventFrame", nil, itemList, {
        "MinimalScrollBar",
    })
    if scrollBoxTemplate and scrollBarTemplate then
        scrollBox:SetFrameLevel(itemList:GetFrameLevel() + 1)
        scrollBar:SetFrameLevel(itemList:GetFrameLevel() + 2)
        itemList.ScrollBox = scrollBox
        itemList.ScrollBar = scrollBar
    else
        if scrollBox and scrollBox.Hide then
            scrollBox:Hide()
        end
        if scrollBar and scrollBar.Hide then
            scrollBar:Hide()
        end
    end
    itemList:Show()

    local groupHeaderParent = itemList.HeaderContainer or groupPreviewFrame
    if groupHeaderParent and groupHeaderParent.SetHeight then
        groupHeaderParent:SetHeight(GROUP_LIST_HEADER_HEIGHT)
    end

    local groupHeaderFrame = createHeaderFrame(groupPreviewFrame, {
        tabKey = tabKey,
        columnWidths = options.columnWidths,
        lastColumnText = options.lastColumnText,
    })
    groupHeaderFrame:SetParent(groupPreviewFrame)
    groupHeaderFrame:ClearAllPoints()
    groupHeaderFrame:SetPoint("TOPLEFT", itemList, "TOPLEFT", GROUP_LIST_ROWS_PADDING_X, 0)
    groupHeaderFrame:SetPoint("TOPRIGHT", itemList, "TOPRIGHT", -GROUP_LIST_ROWS_PADDING_X, 0)
    groupHeaderFrame:SetHeight(GROUP_LIST_HEADER_HEIGHT)
    groupHeaderFrame:SetFrameLevel(itemList:GetFrameLevel() + 2)
    groupHeaderFrame:Show()

    local groupEmpty = itemList:CreateFontString(nil, "OVERLAY", "GameFontDisable")
    groupEmpty:SetText(TRANSLATE("没有找到已共享钥石数据的队伍成员"))
    groupEmpty:SetJustifyH("CENTER")
    groupEmpty:SetJustifyV("MIDDLE")
    if core.ApplyPanelEmptyPromptStyle then
        core.ApplyPanelEmptyPromptStyle(groupEmpty)
    end

    local widgets
    local groupScrollBoxReady = false
    if itemList.ScrollBox and itemList.ScrollBar and ScrollUtil and CreateScrollBoxListLinearView then
        local view = CreateScrollBoxListLinearView(0, 0, GROUP_LIST_ROWS_PADDING_X, GROUP_LIST_ROWS_PADDING_X, 0)
        if view.SetElementExtent then
            view:SetElementExtent(GROUP_LIST_ROW_HEIGHT)
        end
        view:SetElementInitializer("Button", function(row, elementData)
            owner:InitializeGroupCharacterRowFrame(row)
            owner:ApplyGroupColumnWidthsToRow(widgets, row)
            if elementData and elementData.characterEntry then
                owner:RefreshGroupCharacterRowFrame(row, elementData.characterEntry, elementData.displayState)
            else
                owner:SetGroupRowFrameVisible(row, false)
            end
        end)
        ScrollUtil.InitScrollBoxListWithScrollBar(itemList.ScrollBox, itemList.ScrollBar, view)
        groupScrollBoxReady = true
    end

    widgets = {
        tabGroup = owner.widgets and owner.widgets.tabGroup or tabGroup,
        root = groupPreviewFrame,
        groupContainer = groupPreviewFrame,
        groupPreviewFrame = groupPreviewFrame,
        groupBrowseFrame = itemList,
        groupBrowseLeftOffset = groupBrowseLeftOffset,
        groupBrowseTopOffset = groupBrowseTopOffset,
        groupBrowseRightOffset = groupBrowseRightOffset,
        groupBrowseBottomOffset = groupBrowseBottomOffset,
        groupBrowseCenterList = groupBrowseCenterList,
        groupBrowseMaxWidth = groupBrowseMaxWidth,
        groupHeaderRowGap = groupHeaderRowGap,
        groupScrollBarWidth = groupScrollBarWidth,
        groupScrollBarXOffset = groupScrollBarXOffset,
        groupScrollBarTopInset = groupScrollBarTopInset,
        groupScrollBarBottomInset = groupScrollBarBottomInset,
        groupItemList = itemList,
        groupScrollBox = groupScrollBoxReady and itemList.ScrollBox or nil,
        groupScrollBar = groupScrollBoxReady and itemList.ScrollBar or nil,
        groupContent = groupScrollBoxReady and itemList.ScrollBox or groupPreviewFrame,
        groupEmpty = groupEmpty,
        groupHeaderFrame = groupHeaderFrame,
        groupRowsFrame = groupScrollBoxReady and itemList.ScrollBox or itemList,
        groupRowFrames = {},
        groupListKind = tabKey,
        groupBaseColumnWidths = options.columnWidths,
        groupEmptyText = options.emptyText,
    }

    owner.widgets = widgets
    owner.tabViews = owner.tabViews or {}
    owner.tabViews[tabKey] = widgets
    if tabKey == "group" or tabKey == "carpool" then
        widgets.groupRefreshButton = CreateGroupRefreshButton(owner, groupPreviewFrame, widgets, tabKey)
    end
    layoutGroupListPanel(widgets)

    if core.ApplyThemeToTabGroup then
        core.ApplyThemeToTabGroup(tabGroup)
    end
    if core.ApplyFontToFrame then
        core.ApplyFontToFrame(groupPreviewFrame)
    end
    groupPreviewFrame:Show()

    C_Timer.After(0, function()
        if owner.activeTab == tabKey and owner.widgets == widgets then
            layoutGroupListPanel(owner.widgets)
        end
    end)

    owner:RefreshMainWindow("BuildSelectedTab", tabKey)
end

function GroupTab.Build(owner, tabGroup)
    GroupTab.BuildList(owner, tabGroup, {
        tabKey = "group",
        centerList = true,
        emptyText = TRANSLATE("没有找到已共享钥石数据的队伍成员"),
    })
end
