local _, ns = ...
local L = ns.L or {}

local NavigationTabs = {}
ns.UINavigationTabs = NavigationTabs

local VERTICAL_SUBTAB_MAIN_TABS = {
    pve = true,
    pvp = true,
    systems = true,
    raids = true,
}

function NavigationTabs.Install(UI, helpers)
    if type(UI) ~= "table" then
        return
    end

    helpers = helpers or {}
    local MAIN_TABS = helpers.MAIN_TABS or {}
    local SUB_TABS = helpers.SUB_TABS or {}

    local function isSubTabVisible(subTabData)
        if type(subTabData) ~= "table" then
            return false
        end

        if type(subTabData.visible) ~= "function" then
            return true
        end

        local ok, visible = pcall(subTabData.visible)
        return ok and visible == true
    end

    local function getVisibleSubTabs(mainTab)
        local visibleTabs = {}
        for _, subTabData in ipairs(SUB_TABS[mainTab] or {}) do
            if isSubTabVisible(subTabData) then
                visibleTabs[#visibleTabs + 1] = subTabData
            end
        end

        return visibleTabs
    end

    function UI:GetSubTabCount(mainTab)
        return #getVisibleSubTabs(mainTab)
    end

    function UI:ShouldShowSubTabs(mainTab)
        return self:GetSubTabCount(mainTab) > 1
    end

    function UI:UsesVerticalSubTabs(mainTab)
        return VERTICAL_SUBTAB_MAIN_TABS[mainTab] == true and self:ShouldShowSubTabs(mainTab)
    end

    function UI:UsesHorizontalSubTabs(mainTab)
        return self:ShouldShowSubTabs(mainTab) and not self:UsesVerticalSubTabs(mainTab)
    end

    local function getButtonWidth(button)
        return math.ceil((button and (button.vlDesiredWidth or button:GetWidth())) or 0)
    end

    local function setTabState(button, isActive)
        if not button then
            return
        end

        if button.SetActive then
            button:SetActive(isActive)
        else
            if isActive then
                button:Disable()
            else
                button:Enable()
            end
        end
    end

    local function resetVerticalSubTabButton(button)
        if not button then
            return
        end

        button:SetHeight(34)
        button:SetAlpha(1)
        if button.SetBackdropColor then
            button:SetBackdropColor(0.07, 0.06, 0.055, 0.96)
            button:SetBackdropBorderColor(0.40, 0.31, 0.10, 0.46)
        end
        if button.bg then
            button.bg:SetAlpha(1)
        end
        if button.innerShade then
            button.innerShade:SetAlpha(1)
        end
        if button.bottomLine then
            button.bottomLine:SetAlpha(0)
            button.bottomLine:Hide()
        end
        if button.label then
            button.label:SetJustifyH("CENTER")
            button.label:ClearAllPoints()
            button.label:SetPoint("LEFT", 12, 0)
            button.label:SetPoint("RIGHT", -12, 0)
        end
    end

    local function setVerticalHeadingButton(button)
        if not button then
            return
        end

        button:SetHeight(20)
        button:Disable()
        button.subTabKey = nil
        button.mainTabKey = nil
        button:SetScript("OnClick", nil)
        if button.SetBackdropColor then
            button:SetBackdropColor(0, 0, 0, 0)
            button:SetBackdropBorderColor(0, 0, 0, 0)
        end
        if button.bg then
            button.bg:SetAlpha(0)
        end
        if button.innerShade then
            button.innerShade:SetAlpha(0)
        end
        if button.hover then
            button.hover:SetAlpha(0)
        end
        if button.activeFill then
            button.activeFill:SetAlpha(0)
        end
        if button.bottomLine then
            button.bottomLine:SetAlpha(0.55)
            button.bottomLine:Show()
        end
        if button.label then
            button.label:SetJustifyH("LEFT")
            button.label:ClearAllPoints()
            button.label:SetPoint("LEFT", 8, 0)
            button.label:SetPoint("RIGHT", -8, 0)
            button.label:SetTextColor(0.92, 0.76, 0.24, 0.92)
        end
    end

    function UI:RefreshMainTabs()
        if not self.frame then
            return
        end

        local selectedMainTab = ns:GetSelectedMainTab()
        local transientMode = self.GetTransientPanelMode and self:GetTransientPanelMode() or nil
        local gap = 4
        local availableWidth = math.floor(self.frame.mainTabBar:GetWidth() or 0)
        local navButtons = {}

        for index, button in ipairs(self.frame.mainTabs or {}) do
            local tabData = MAIN_TABS[index]
            if tabData then
                local isVisible = not ns.IsMainTabEnabled or ns:IsMainTabEnabled(tabData.key)
                if isVisible then
                    local labelText = tabData.label()
                    if button.SetButtonText then
                        button:SetButtonText(labelText)
                    else
                        button:SetText(labelText)
                    end
                    button:Show()
                    navButtons[#navButtons + 1] = button
                    setTabState(button, transientMode == nil and button.tabKey == selectedMainTab)
                else
                    button:Hide()
                end
            else
                button:Hide()
            end
        end

        if self.frame.featuresButton then
            self.frame.featuresButton:SetButtonText(L.FEATURES_BUTTON or "Features")
            navButtons[#navButtons + 1] = self.frame.featuresButton
        end
        if self.frame.settingsButton then
            self.frame.settingsButton:SetButtonText(L.SETTINGS_BUTTON or "Options")
            navButtons[#navButtons + 1] = self.frame.settingsButton
        end
        if self.frame.wishlistButton then
            self.frame.wishlistButton:SetButtonText("")
            navButtons[#navButtons + 1] = self.frame.wishlistButton
        end

        if availableWidth > 0 and #navButtons > 1 then
            local buttonWidthTotal = 0
            for _, button in ipairs(navButtons) do
                buttonWidthTotal = buttonWidthTotal + getButtonWidth(button)
            end

            if buttonWidthTotal + (gap * (#navButtons - 1)) > availableWidth then
                if buttonWidthTotal < availableWidth then
                    gap = math.max(2, math.floor((availableWidth - buttonWidthTotal) / (#navButtons - 1)))
                else
                    gap = 2
                end
            end
        end

        for index, button in ipairs(navButtons) do
            button:ClearAllPoints()
            if index == 1 then
                button:SetPoint("TOPLEFT", self.frame.mainTabBar, "TOPLEFT", 0, 0)
            else
                button:SetPoint("LEFT", navButtons[index - 1], "RIGHT", gap, 0)
            end
        end
    end

    function UI:RefreshSubTabs()
        if not self.frame then
            return
        end

        local transientMode = self.GetTransientPanelMode and self:GetTransientPanelMode() or nil
        if transientMode then
            if self.frame.subTabBar then
                self.frame.subTabBar:Hide()
            end
            for _, button in ipairs(self.frame.subTabs or {}) do
                button:Hide()
            end
            if self.frame.verticalSubTabRail then
                self.frame.verticalSubTabRail:Hide()
            end
            for _, button in ipairs(self.frame.verticalSubTabs or {}) do
                button:Hide()
            end
            return
        end

        local selectedMainTab = ns:GetSelectedMainTab()
        local subTabs = getVisibleSubTabs(selectedMainTab)
        local selectedSubTab = ns:GetSelectedSubTab(selectedMainTab)
        local hasSelectedSubTab = false
        for _, subTabData in ipairs(subTabs) do
            if subTabData.key == selectedSubTab then
                hasSelectedSubTab = true
                break
            end
        end
        if not hasSelectedSubTab and subTabs[1] then
            ns:SetSelectedSubTab(selectedMainTab, subTabs[1].key)
            return
        end

        if not self:ShouldShowSubTabs(selectedMainTab) then
            if self.frame.subTabBar then
                self.frame.subTabBar:Hide()
            end
            for _, button in ipairs(self.frame.subTabs or {}) do
                button:Hide()
            end
            if self.frame.verticalSubTabRail then
                self.frame.verticalSubTabRail:Hide()
            end
            for _, button in ipairs(self.frame.verticalSubTabs or {}) do
                button:Hide()
            end
            return
        end

        if self:UsesVerticalSubTabs(selectedMainTab) then
            if self.frame.subTabBar then
                self.frame.subTabBar:Hide()
            end
            for _, button in ipairs(self.frame.subTabs or {}) do
                button:Hide()
            end
            if self.frame.verticalSubTabRail then
                self.frame.verticalSubTabRail:Show()
            end

            local previousButton
            for index, button in ipairs(self.frame.verticalSubTabs or {}) do
                local subTabData = subTabs[index]
                if subTabData then
                    local labelText = subTabData.label()
                    if button.SetButtonText then
                        button:SetButtonText(labelText)
                    else
                        button:SetText(labelText)
                    end
                    button:ClearAllPoints()
                    local topGap = subTabData.heading == true and -18 or -8
                    if previousButton then
                        button:SetPoint("TOPLEFT", previousButton, "BOTTOMLEFT", 0, topGap)
                        button:SetPoint("TOPRIGHT", previousButton, "BOTTOMRIGHT", 0, topGap)
                    else
                        button:SetPoint("TOPLEFT", self.frame.verticalSubTabRail, "TOPLEFT", 12, -14)
                        button:SetPoint("TOPRIGHT", self.frame.verticalSubTabRail, "TOPRIGHT", -12, -14)
                    end
                    if subTabData.heading == true then
                        setVerticalHeadingButton(button)
                    else
                        resetVerticalSubTabButton(button)
                        button.subTabKey = subTabData.key
                        button.mainTabKey = selectedMainTab
                        button:SetScript("OnClick", function(selfButton)
                            ns:SetSelectedSubTab(selfButton.mainTabKey, selfButton.subTabKey)
                        end)
                        setTabState(button, subTabData.key == selectedSubTab)
                    end
                    button:Show()
                    previousButton = button
                else
                    button:Hide()
                end
            end
            return
        end

        if self.frame.verticalSubTabRail then
            self.frame.verticalSubTabRail:Hide()
        end
        for _, button in ipairs(self.frame.verticalSubTabs or {}) do
            button:Hide()
        end
        if self.frame.subTabBar then
            self.frame.subTabBar:Show()
        end

        local gap = #subTabs >= 7 and 4 or (#subTabs >= 6 and 6 or 6)
        local availableWidth = math.floor(self.frame.subTabBar:GetWidth() or 0)
        if availableWidth <= 0 and self.frame.content then
            availableWidth = math.floor((self.frame.content:GetWidth() or 0) - 18)
        end

        local visibleButtons = {}
        local maxDesiredWidth = 0
        local totalDesiredWidth = 0

        for index, button in ipairs(self.frame.subTabs or {}) do
            local subTabData = subTabs[index]
            if subTabData then
                local labelText = subTabData.label()
                if button.SetButtonText then
                    button:SetButtonText(labelText)
                else
                    button:SetText(labelText)
                end
                local desiredWidth = getButtonWidth(button)
                maxDesiredWidth = math.max(maxDesiredWidth, desiredWidth)
                totalDesiredWidth = totalDesiredWidth + desiredWidth
                visibleButtons[#visibleButtons + 1] = button
                button.subTabKey = subTabData.key
                button.mainTabKey = selectedMainTab
                button:SetScript("OnClick", function(selfButton)
                    ns:SetSelectedSubTab(selfButton.mainTabKey, selfButton.subTabKey)
                end)
                setTabState(button, subTabData.key == selectedSubTab)
                button:Show()
            else
                button:Hide()
            end
        end

        local targetWidth
        if #visibleButtons > 1 and availableWidth > 0 then
            local totalGap = gap * math.max(0, #visibleButtons - 1)
            local evenWidth = math.floor((availableWidth - totalGap) / #visibleButtons)
            local cappedEvenWidth = math.min(188, evenWidth)
            local balancedWidth = math.max(maxDesiredWidth, cappedEvenWidth)

            if (balancedWidth * #visibleButtons) + totalGap <= availableWidth then
                targetWidth = balancedWidth
            elseif totalDesiredWidth + totalGap > availableWidth then
                if totalDesiredWidth < availableWidth then
                    gap = math.max(2, math.floor((availableWidth - totalDesiredWidth) / (#visibleButtons - 1)))
                else
                    gap = 2
                end
            end
        end

        for index, button in ipairs(visibleButtons) do
            if targetWidth then
                button:SetWidth(targetWidth)
            end
            button:ClearAllPoints()
            if index == 1 then
                button:SetPoint("LEFT", 0, 0)
            else
                button:SetPoint("LEFT", visibleButtons[index - 1], "RIGHT", gap, 0)
            end
        end
    end
end
