GuildHelper = GuildHelper or {}

local addon = GuildHelper

addon.NewUIShell = addon.NewUIShell or {}

local theme = addon.NewUITheme or {
    Shell = {
        Background = { 0.08, 0.07, 0.05, 0.995 },
        Border = { 0.62, 0.48, 0.16, 1 },
        TitleBar = { 0.18, 0.14, 0.08, 0.96 },
        TabRow = { 0.22, 0.17, 0.10, 0.92 },
        CloseButton = { 0.22, 0.12, 0.10, 0.95 },
        CloseBorder = { 0.70, 0.52, 0.22, 1 },
        Text = { 0.96, 0.93, 0.84, 1 },
        MutedText = { 0.72, 0.68, 0.58, 1 },
    },
}

local shell = addon.NewUIShell

local BASE_SHELL_SCREEN_WIDTH = 1920
local BASE_SHELL_SCREEN_HEIGHT = 1080
local BASE_SHELL_FRAME_WIDTH = 1448
local BASE_SHELL_FRAME_HEIGHT = 888
local DEFAULT_SHELL_SIZE_KEY = "1920x1080"
local SUPPORTED_SHELL_SIZES = {
    { key = "1920x1080", label = "1920 x 1080", width = 1920, height = 1080 },
    { key = "2560x1440", label = "2560 x 1440", width = 2560, height = 1440 },
    { key = "3200x1800", label = "3200 x 1800", width = 3200, height = 1800 },
    { key = "3840x2160", label = "3840 x 2160", width = 3840, height = 2160 },
}

local function getNewUIProfile()
    local profile = addon.Store and addon.Store.GetProfile and addon.Store:GetProfile() or nil

    if type(profile) ~= "table" then
        return nil
    end

    profile.ui = profile.ui or {}
    profile.ui.newUI = profile.ui.newUI or {}
    return profile.ui.newUI
end

local function getConfiguredShellTransparencyAlpha()
    if addon.NewUISettings and addon.NewUISettings.GetConfiguredTransparencyAlpha then
        return math.max(0.60, math.min(1, tonumber(addon.NewUISettings:GetConfiguredTransparencyAlpha("mainUi")) or 1))
    end

    return 1
end

local function getSupportedShellSize(sizeKey)
    local resolvedKey = tostring(sizeKey or DEFAULT_SHELL_SIZE_KEY)

    for _, option in ipairs(SUPPORTED_SHELL_SIZES) do
        if option.key == resolvedKey then
            return option
        end
    end

    return SUPPORTED_SHELL_SIZES[1]
end

local function getDesiredShellScale(sizeOption)
    local option = getSupportedShellSize(sizeOption and sizeOption.key or sizeOption)
    local widthScale = (tonumber(option.width) or BASE_SHELL_SCREEN_WIDTH) / BASE_SHELL_SCREEN_WIDTH
    local heightScale = (tonumber(option.height) or BASE_SHELL_SCREEN_HEIGHT) / BASE_SHELL_SCREEN_HEIGHT
    return math.min(widthScale, heightScale)
end

local function getAvailableShellScale()
    local parentWidth = UIParent and UIParent.GetWidth and tonumber(UIParent:GetWidth()) or BASE_SHELL_FRAME_WIDTH
    local parentHeight = UIParent and UIParent.GetHeight and tonumber(UIParent:GetHeight()) or BASE_SHELL_FRAME_HEIGHT
    local widthScale = math.max((parentWidth - 32) / BASE_SHELL_FRAME_WIDTH, 0.5)
    local heightScale = math.max((parentHeight - 32) / BASE_SHELL_FRAME_HEIGHT, 0.5)
    return math.min(widthScale, heightScale)
end

local function resolveShellTexturePath(textureKeyOrPath)
    if type(textureKeyOrPath) ~= "string" or textureKeyOrPath == "" then
        return nil
    end

    local textures = addon.NewUIAssets and addon.NewUIAssets.Textures or nil
    if textures and textures[textureKeyOrPath] ~= nil then
        return textures[textureKeyOrPath] ~= "" and textures[textureKeyOrPath] or nil
    end

    return textureKeyOrPath
end

local function resolveShellArtMetrics(textureKey)
    local metrics = addon.NewUIAssets and addon.NewUIAssets.Metrics or nil
    return metrics and metrics[textureKey] or nil
end

local function applyShellTexture(texture, assetKey, fallbackColor)
    local texturePath = resolveShellTexturePath(assetKey)
    local metrics = resolveShellArtMetrics(assetKey)

    if texturePath then
        texture:SetTexture(texturePath)
        texture:SetVertexColor(1, 1, 1, 1)
        if metrics and type(metrics.texCoord) == "table" and #metrics.texCoord == 4 then
            texture:SetTexCoord(metrics.texCoord[1], metrics.texCoord[3], metrics.texCoord[2], metrics.texCoord[4])
        else
            texture:SetTexCoord(0, 1, 0, 1)
        end
        return
    end

    texture:SetColorTexture(unpack(fallbackColor))
end

local function CreateShellBackdrop(frame)
    local edgeThickness = 34
    local cornerSize = 112
    local edgeStart = cornerSize - 16

    if frame.SetBackdrop then
        frame:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8X8",
            edgeFile = "Interface\\Buttons\\WHITE8X8",
            edgeSize = 1,
            insets = {
                left = 1,
                right = 1,
                top = 1,
                bottom = 1,
            },
        })
        frame:SetBackdropColor(0, 0, 0, 0)
        frame:SetBackdropBorderColor(0, 0, 0, 0)
    end

    local backgroundArt = CreateFrame("Frame", nil, frame)
    backgroundArt:SetAllPoints(frame)
    backgroundArt:SetFrameLevel(frame:GetFrameLevel() + 1)

    local borderArt = CreateFrame("Frame", nil, frame)
    borderArt:SetAllPoints(frame)
    borderArt:SetFrameLevel(frame:GetFrameLevel() + 8)

    local underlay = backgroundArt:CreateTexture(nil, "BACKGROUND")
    underlay:SetAllPoints(frame)
    underlay:SetColorTexture(0.06, 0.05, 0.04, 0.98)

    local center = backgroundArt:CreateTexture(nil, "ARTWORK")
    center:SetAllPoints(frame)
    applyShellTexture(center, "ShellFrameCenter", theme.Shell.Background)
    center:SetVertexColor(1, 1, 1, 1)

    local top = borderArt:CreateTexture(nil, "ARTWORK")
    top:SetPoint("TOPLEFT", frame, "TOPLEFT", edgeStart, 0)
    top:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -edgeStart, 0)
    top:SetHeight(edgeThickness)
    applyShellTexture(top, "ShellFrameTopEdge", theme.Shell.Border)

    local bottom = borderArt:CreateTexture(nil, "ARTWORK")
    bottom:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", edgeStart, 0)
    bottom:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -edgeStart, 0)
    bottom:SetHeight(edgeThickness)
    applyShellTexture(bottom, "ShellFrameBottomEdge", theme.Shell.Border)

    local left = borderArt:CreateTexture(nil, "ARTWORK")
    left:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, -edgeStart)
    left:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 0, edgeStart)
    left:SetWidth(edgeThickness)
    applyShellTexture(left, "ShellFrameLeftEdge", theme.Shell.Border)

    local right = borderArt:CreateTexture(nil, "ARTWORK")
    right:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, -edgeStart)
    right:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 0, edgeStart)
    right:SetWidth(edgeThickness)
    applyShellTexture(right, "ShellFrameRightEdge", theme.Shell.Border)

    local topLeft = borderArt:CreateTexture(nil, "ARTWORK")
    topLeft:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, 0)
    topLeft:SetSize(cornerSize, cornerSize)
    applyShellTexture(topLeft, "ShellFrameTopLeft", theme.Shell.Border)

    local topRight = borderArt:CreateTexture(nil, "ARTWORK")
    topRight:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, 0)
    topRight:SetSize(cornerSize, cornerSize)
    applyShellTexture(topRight, "ShellFrameTopRight", theme.Shell.Border)

    local bottomLeft = borderArt:CreateTexture(nil, "ARTWORK")
    bottomLeft:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 0, 0)
    bottomLeft:SetSize(cornerSize, cornerSize)
    applyShellTexture(bottomLeft, "ShellFrameBottomLeft", theme.Shell.Border)

    local bottomRight = borderArt:CreateTexture(nil, "ARTWORK")
    bottomRight:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 0, 0)
    bottomRight:SetSize(cornerSize, cornerSize)
    applyShellTexture(bottomRight, "ShellFrameBottomRight", theme.Shell.Border)

    frame.ShellBackgroundArt = backgroundArt
    frame.ShellBorderArt = borderArt
    frame.ShellUnderlay = underlay
    frame.background = center
end

function shell:GetSupportedSizeOptions()
    return SUPPORTED_SHELL_SIZES
end

function shell:GetConfiguredSizeOption()
    local profile = getNewUIProfile()
    return getSupportedShellSize(profile and profile.sizeKey or DEFAULT_SHELL_SIZE_KEY)
end

function shell:GetConfiguredScale()
    local desiredScale = getDesiredShellScale(self:GetConfiguredSizeOption())
    local availableScale = getAvailableShellScale()
    local smallestScale = getDesiredShellScale(SUPPORTED_SHELL_SIZES[1])
    local largestScale = getDesiredShellScale(SUPPORTED_SHELL_SIZES[#SUPPORTED_SHELL_SIZES])

    if availableScale >= desiredScale then
        return desiredScale
    end

    if availableScale <= smallestScale then
        return availableScale
    end

    local lowerBound = smallestScale

    for _, option in ipairs(SUPPORTED_SHELL_SIZES) do
        local optionScale = getDesiredShellScale(option)

        if optionScale <= availableScale then
            lowerBound = optionScale
        else
            break
        end
    end

    if desiredScale <= lowerBound then
        return desiredScale
    end

    local progress = (desiredScale - lowerBound) / math.max(largestScale - lowerBound, 0.0001)
    return lowerBound + ((availableScale - lowerBound) * progress)
end

function shell:ApplyConfiguredSize()
    if not self.frame then
        return nil
    end

    self.frame:SetSize(BASE_SHELL_FRAME_WIDTH, BASE_SHELL_FRAME_HEIGHT)
    self.frame:SetScale(self:GetConfiguredScale())
    self.frame:ClearAllPoints()
    self.frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
    return self.frame
end

function shell:SetConfiguredSize(sizeKey)
    local profile = getNewUIProfile()
    local option = getSupportedShellSize(sizeKey)

    if profile then
        profile.sizeKey = option.key
    end

    self:ApplyConfiguredSize()
    return option
end

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

    local textureKey = isActive and "ShellTabSelected" or "ShellTabNormal"
    local backgroundColor = isActive and { 0.28, 0.22, 0.12, 0.98 } or { 0.18, 0.15, 0.09, 0.92 }

    if not button.Background then
        button.Background = button:CreateTexture(nil, "BACKGROUND")
        button.Background:SetAllPoints(button)
    end

    applyShellTexture(button.Background, textureKey, backgroundColor)

    local activeColor = { 0.94, 0.82, 0.34, 1 }
    local inactiveColor = { 0.84, 0.77, 0.63, 0.94 }
    local color = isActive and activeColor or inactiveColor
    button.LabelText:SetTextColor(color[1], color[2], color[3], color[4])
end

local function CreateContentHost(parent)
    local contentHost = CreateFrame("Frame", nil, parent)
    if parent and parent.GetFrameStrata and contentHost.SetFrameStrata then
        contentHost:SetFrameStrata(parent:GetFrameStrata())
    end
    contentHost:SetPoint("TOPLEFT", parent, "TOPLEFT", 34, -144)
    contentHost:SetSize(1380, 742)
    return contentHost
end

local function ClearContentHost(contentHost)
    if not contentHost then
        return
    end

    local children = { contentHost:GetChildren() }
    local regions = { contentHost:GetRegions() }

    for _, region in ipairs(regions) do
        if region and region.Hide then
            region:Hide()
        end

        if region and region.SetParent then
            region:SetParent(nil)
        end
    end

    for _, child in ipairs(children) do
        if child and child.Hide then
            child:Hide()
        end

        if child and child.SetParent then
            child:SetParent(nil)
        end
    end
end

local function CreateTabButton(parent, label, x, isActive, onClick)
    local button = CreateFrame("Button", nil, parent, "BackdropTemplate")
    button:SetSize(142, 36)
    button:SetPoint("LEFT", parent, "LEFT", x, 0)

    local labelText = button:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    labelText:SetPoint("CENTER", button, "CENTER", 0, -1)
    labelText:SetText(label)
    button.LabelText = labelText
    ApplyShellTabStyle(button, isActive)

    button:SetScript("OnEnter", function()
        if not button.isActive and not button.HighlightTexture then
            button.HighlightTexture = button:CreateTexture(nil, "ARTWORK")
            button.HighlightTexture:SetAllPoints(button)
        end

        if not button.isActive and button.HighlightTexture then
            applyShellTexture(button.HighlightTexture, "ShellTabHover", { 0.24, 0.20, 0.12, 0.72 })
            button.HighlightTexture:Show()
        end
    end)

    button:SetScript("OnLeave", function()
        if button.HighlightTexture then
            button.HighlightTexture:Hide()
        end
    end)

    button:SetScript("OnClick", function()
        if onClick then
            onClick()
        end
    end)

    return button
end

local function navigateShellTab(viewKey, pageName)
    if addon.Router and type(addon.Router.Navigate) == "function" and type(viewKey) == "string" and viewKey ~= "" then
        addon.Router:Navigate(viewKey)
        return
    end

    shell:ShowPage(pageName)
end

local function CreateTitleArea(parent)
    local titleBar = CreateFrame("Frame", nil, parent)
    titleBar:SetPoint("TOPLEFT", parent, "TOPLEFT", 0, 0)
    titleBar:SetPoint("TOPRIGHT", parent, "TOPRIGHT", 0, 0)
    titleBar:SetHeight(96)
    if parent and parent.GetFrameStrata and titleBar.SetFrameStrata then
        titleBar:SetFrameStrata(parent:GetFrameStrata())
    end
    titleBar:EnableMouse(true)
    titleBar:RegisterForDrag("LeftButton")

    local titleBackground = titleBar:CreateTexture(nil, "BACKGROUND")
    titleBackground:SetAllPoints(titleBar)
    titleBackground:SetColorTexture(0, 0, 0, 0)

    local ornamentFrame = CreateFrame("Frame", nil, titleBar)
    ornamentFrame:SetAllPoints(titleBar)
    if titleBar.GetFrameStrata and ornamentFrame.SetFrameStrata then
        ornamentFrame:SetFrameStrata(titleBar:GetFrameStrata())
    end

    local headerArt = ornamentFrame:CreateTexture(nil, "OVERLAY")
    headerArt:SetPoint("TOP", titleBar, "TOP", 0, -4)
    headerArt:SetSize(900, 68)
    headerArt:SetDrawLayer("OVERLAY", 2)
    applyShellTexture(headerArt, "ShellHeaderMain", { 0.22, 0.17, 0.10, 0.96 })

    local titleText = "GuildHelper V3 Dashboard"

    local titleShadow = ornamentFrame:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
    titleShadow:SetPoint("CENTER", headerArt, "CENTER", 2, -3)
    titleShadow:SetText(titleText)
    titleShadow:SetTextColor(0.10, 0.05, 0.01, 0.95)
    titleShadow:SetScale(1.18)

    local titleGlow = ornamentFrame:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
    titleGlow:SetPoint("CENTER", headerArt, "CENTER", -1, 1)
    titleGlow:SetText(titleText)
    titleGlow:SetTextColor(1, 0.94, 0.70, 0.30)
    titleGlow:SetScale(1.18)

    local title = ornamentFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("CENTER", headerArt, "CENTER", 0, -1)
    title:SetText(titleText)
    title:SetTextColor(0.96, 0.83, 0.34, 1)
    title:SetScale(1.18)
    title:SetShadowColor(0, 0, 0, 0.9)
    title:SetShadowOffset(1, -1)

    local subtitleStrip = ornamentFrame:CreateTexture(nil, "OVERLAY")
    subtitleStrip:SetPoint("TOP", title, "BOTTOM", 0, -7)
    subtitleStrip:SetSize(700, 10)
    subtitleStrip:SetDrawLayer("OVERLAY", 2)
    applyShellTexture(subtitleStrip, "ShellSubtitleStrip", { 0.18, 0.14, 0.08, 0.72 })

    local flourishLeft = ornamentFrame:CreateTexture(nil, "OVERLAY")
    flourishLeft:SetPoint("RIGHT", subtitleStrip, "LEFT", -8, -2)
    flourishLeft:SetSize(150, 42)
    flourishLeft:SetDrawLayer("OVERLAY", 2)
    applyShellTexture(flourishLeft, "ShellHeaderFlourishLeft", { 0.62, 0.48, 0.16, 0.85 })

    local flourishRight = ornamentFrame:CreateTexture(nil, "OVERLAY")
    flourishRight:SetPoint("LEFT", subtitleStrip, "RIGHT", 8, -2)
    flourishRight:SetSize(150, 42)
    flourishRight:SetDrawLayer("OVERLAY", 2)
    applyShellTexture(flourishRight, "ShellHeaderFlourishRight", { 0.62, 0.48, 0.16, 0.85 })

    local subtitle = ornamentFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    subtitle:SetPoint("TOP", subtitleStrip, "BOTTOM", 0, -3)
    subtitle:SetText("Guild summary, events, readiness, and Mythic+ progress")
    subtitle:SetTextColor(0.86, 0.79, 0.65, 1)

    local divider = ornamentFrame:CreateTexture(nil, "OVERLAY")
    divider:SetPoint("BOTTOMLEFT", titleBar, "BOTTOMLEFT", 20, 2)
    divider:SetPoint("BOTTOMRIGHT", titleBar, "BOTTOMRIGHT", -20, 2)
    divider:SetHeight(4)
    applyShellTexture(divider, "ShellDividerGold", { 0.62, 0.48, 0.16, 0.85 })
    divider:SetVertexColor(1, 1, 1, 0.68)

    local closeButton = CreateFrame("Button", nil, titleBar, "BackdropTemplate")
    closeButton:SetSize(44, 44)
    closeButton:SetPoint("TOPRIGHT", titleBar, "TOPRIGHT", -10, -8)

    local closeTexture = closeButton:CreateTexture(nil, "BACKGROUND")
    closeTexture:SetAllPoints(closeButton)
    applyShellTexture(closeTexture, "ShellCloseButton", theme.Shell.CloseButton)
    closeButton.Texture = closeTexture

    closeButton:SetScript("OnEnter", function()
        applyShellTexture(closeTexture, "ShellCloseButtonHover", theme.Shell.CloseBorder)
    end)

    closeButton:SetScript("OnLeave", function()
        applyShellTexture(closeTexture, "ShellCloseButton", theme.Shell.CloseButton)
    end)

    closeButton:SetScript("OnClick", function()
        if parent then
            parent:Hide()
        end
    end)

    titleBar:SetScript("OnDragStart", function()
        if parent and parent.StartMoving then
            shell.isDragging = true
            parent:StartMoving()
        end
    end)

    titleBar:SetScript("OnDragStop", function()
        if parent and parent.StopMovingOrSizing then
            parent:StopMovingOrSizing()
        end
        shell.isDragging = false
    end)

    titleBar.TitleShadow = titleShadow
    titleBar.TitleGlow = titleGlow
    titleBar.TitleText = title
    titleBar.SubtitleText = subtitle
    titleBar.OrnamentFrame = ornamentFrame
    titleBar.HeaderArt = headerArt
    titleBar.SubtitleStrip = subtitleStrip
    titleBar.FlourishLeft = flourishLeft
    titleBar.FlourishRight = flourishRight
    titleBar.Divider = divider
    titleBar.CloseButton = closeButton
    return titleBar
end

local function CreateTabRow(parent)
    local tabRow = CreateFrame("Frame", nil, parent)
    if parent and parent.GetFrameStrata and tabRow.SetFrameStrata then
        tabRow:SetFrameStrata(parent:GetFrameStrata())
    end
    tabRow:SetPoint("TOPLEFT", parent, "TOPLEFT", 0, -98)
    tabRow:SetPoint("TOPRIGHT", parent, "TOPRIGHT", 0, -98)
    tabRow:SetHeight(42)

    local tabBackground = tabRow:CreateTexture(nil, "BACKGROUND")
    tabBackground:SetAllPoints(tabRow)
    tabBackground:SetColorTexture(0, 0, 0, 0)

    local topDivider = tabRow:CreateTexture(nil, "ARTWORK")
    topDivider:SetPoint("TOPLEFT", tabRow, "TOPLEFT", 18, 0)
    topDivider:SetPoint("TOPRIGHT", tabRow, "TOPRIGHT", -18, 0)
    topDivider:SetHeight(2)
    applyShellTexture(topDivider, "ShellDividerGold", { 0.62, 0.48, 0.16, 0.85 })
    topDivider:SetVertexColor(1, 1, 1, 0.25)

    local bottomDivider = tabRow:CreateTexture(nil, "ARTWORK")
    bottomDivider:SetPoint("BOTTOMLEFT", tabRow, "BOTTOMLEFT", 18, 0)
    bottomDivider:SetPoint("BOTTOMRIGHT", tabRow, "BOTTOMRIGHT", -18, 0)
    bottomDivider:SetHeight(2)
    applyShellTexture(bottomDivider, "ShellDividerGold", { 0.62, 0.48, 0.16, 0.65 })
    bottomDivider:SetVertexColor(1, 1, 1, 0.18)

    local activePage = shell.activePage or "home"
    local tabStartX = 28
    local tabSpacing = 118

    local tabHome = CreateTabButton(tabRow, "Home", tabStartX, activePage == "home", function()
        navigateShellTab("dashboard", "home")
    end)

    local tabNews = CreateTabButton(tabRow, "News", tabStartX + tabSpacing, activePage == "news", function()
        navigateShellTab("board", "news")
    end)

    local tabGroups = CreateTabButton(tabRow, "Groups", tabStartX + (tabSpacing * 2), activePage == "groups", function()
        navigateShellTab("groups", "groups")
    end)

    local tabMyToons = CreateTabButton(tabRow, "My Toons", tabStartX + (tabSpacing * 3), activePage == "mytoons", function()
        navigateShellTab("mytoons", "mytoons")
    end)

    local tabRoster = CreateTabButton(tabRow, "Roster", tabStartX + (tabSpacing * 4), activePage == "roster", function()
        navigateShellTab("roster", "roster")
    end)

    local tabBIS = CreateTabButton(tabRow, "BIS", tabStartX + (tabSpacing * 5), activePage == "bis", function()
        navigateShellTab("bis", "bis")
    end)

    local tabMythicPlus = CreateTabButton(tabRow, "Mythic+", tabStartX + (tabSpacing * 6), activePage == "mythicplus", function()
        navigateShellTab("mythics", "mythicplus")
    end)

    local tabRaidBingo = CreateTabButton(tabRow, "Raid Bingo", tabStartX + (tabSpacing * 7), activePage == "raidbingo", function()
        navigateShellTab("raidbingo", "raidbingo")
    end)

    local tabCelebrate = CreateTabButton(tabRow, "Celebrate", tabStartX + (tabSpacing * 8), activePage == "celebrate", function()
        navigateShellTab("celebrations", "celebrate")
    end)

    local tabSettings = CreateTabButton(tabRow, "Settings", tabStartX + (tabSpacing * 9), activePage == "settings", function()
        navigateShellTab("settings", "settings")
    end)

    tabRow.HomeButton = tabHome
    tabRow.NewsButton = tabNews
    tabRow.GroupsButton = tabGroups
    tabRow.MyToonsButton = tabMyToons
    tabRow.RosterButton = tabRoster
    tabRow.BISButton = tabBIS
    tabRow.MythicPlusButton = tabMythicPlus
    tabRow.RaidBingoButton = tabRaidBingo
    tabRow.CelebrateButton = tabCelebrate
    tabRow.SettingsButton = tabSettings
    tabRow.TopDivider = topDivider
    tabRow.BottomDivider = bottomDivider
    tabRow.Buttons = { tabHome, tabNews, tabGroups, tabMyToons, tabRoster, tabBIS, tabMythicPlus, tabRaidBingo, tabCelebrate, tabSettings }

    return tabRow
end

function shell:ApplyConfiguredTransparency()
    if not self.frame then
        return nil
    end

    local alpha = getConfiguredShellTransparencyAlpha()
    local edgeAlpha = math.min(1, alpha + 0.08)

    if self.frame.ShellUnderlay then
        self.frame.ShellUnderlay:SetAlpha(alpha)
    end

    if self.frame.background then
        self.frame.background:SetAlpha(alpha)
    end

    if self.frame.ShellBorderArt then
        self.frame.ShellBorderArt:SetAlpha(edgeAlpha)
    end

    local titleArea = self.frame.TitleArea
    if titleArea then
        if titleArea.HeaderArt then
            titleArea.HeaderArt:SetAlpha(edgeAlpha)
        end
        if titleArea.SubtitleStrip then
            titleArea.SubtitleStrip:SetAlpha(alpha)
        end
        if titleArea.FlourishLeft then
            titleArea.FlourishLeft:SetAlpha(edgeAlpha)
        end
        if titleArea.FlourishRight then
            titleArea.FlourishRight:SetAlpha(edgeAlpha)
        end
        if titleArea.Divider then
            titleArea.Divider:SetAlpha(edgeAlpha)
        end
    end

    local tabRow = self.frame.TabRow
    if tabRow then
        if tabRow.TopDivider then
            tabRow.TopDivider:SetAlpha(alpha)
        end
        if tabRow.BottomDivider then
            tabRow.BottomDivider:SetAlpha(alpha)
        end
        for _, button in ipairs(tabRow.Buttons or {}) do
            if button and button.Background then
                button.Background:SetAlpha(alpha)
            end
        end
    end

    return alpha
end

function shell:ShowPage(pageName)
    if not self.frame or not self.contentHost then
        return nil
    end

    ClearContentHost(self.contentHost)

    if not addon.NewUIRoot then
        return nil
    end

    if pageName == "news" then
        self.activePage = "news"
    elseif pageName == "groups" then
        self.activePage = "groups"
    elseif pageName == "mytoons" then
        self.activePage = "mytoons"
    elseif pageName == "roster" then
        self.activePage = "roster"
    elseif pageName == "bis" then
        self.activePage = "bis"
    elseif pageName == "mythicplus" then
        self.activePage = "mythicplus"
    elseif pageName == "raidbingo" then
        self.activePage = "raidbingo"
    elseif pageName == "celebrate" then
        self.activePage = "celebrate"
    elseif pageName == "settings" then
        self.activePage = "settings"
    else
        self.activePage = "home"
    end

    if self.frame and self.frame.TabRow then
        if self.frame.TabRow.HomeButton then
            self.frame.TabRow.HomeButton.isActive = self.activePage == "home"
            ApplyShellTabStyle(self.frame.TabRow.HomeButton, self.frame.TabRow.HomeButton.isActive)
        end

        if self.frame.TabRow.NewsButton then
            self.frame.TabRow.NewsButton.isActive = self.activePage == "news"
            ApplyShellTabStyle(self.frame.TabRow.NewsButton, self.frame.TabRow.NewsButton.isActive)
        end

        if self.frame.TabRow.GroupsButton then
            self.frame.TabRow.GroupsButton.isActive = self.activePage == "groups"
            ApplyShellTabStyle(self.frame.TabRow.GroupsButton, self.frame.TabRow.GroupsButton.isActive)
        end

        if self.frame.TabRow.MyToonsButton then
            self.frame.TabRow.MyToonsButton.isActive = self.activePage == "mytoons"
            ApplyShellTabStyle(self.frame.TabRow.MyToonsButton, self.frame.TabRow.MyToonsButton.isActive)
        end

        if self.frame.TabRow.RosterButton then
            self.frame.TabRow.RosterButton.isActive = self.activePage == "roster"
            ApplyShellTabStyle(self.frame.TabRow.RosterButton, self.frame.TabRow.RosterButton.isActive)
        end

        if self.frame.TabRow.BISButton then
            self.frame.TabRow.BISButton.isActive = self.activePage == "bis"
            ApplyShellTabStyle(self.frame.TabRow.BISButton, self.frame.TabRow.BISButton.isActive)
        end

        if self.frame.TabRow.MythicPlusButton then
            self.frame.TabRow.MythicPlusButton.isActive = self.activePage == "mythicplus"
            ApplyShellTabStyle(self.frame.TabRow.MythicPlusButton, self.frame.TabRow.MythicPlusButton.isActive)
        end

        if self.frame.TabRow.RaidBingoButton then
            self.frame.TabRow.RaidBingoButton.isActive = self.activePage == "raidbingo"
            ApplyShellTabStyle(self.frame.TabRow.RaidBingoButton, self.frame.TabRow.RaidBingoButton.isActive)
        end

        if self.frame.TabRow.CelebrateButton then
            self.frame.TabRow.CelebrateButton.isActive = self.activePage == "celebrate"
            ApplyShellTabStyle(self.frame.TabRow.CelebrateButton, self.frame.TabRow.CelebrateButton.isActive)
        end

        if self.frame.TabRow.SettingsButton then
            self.frame.TabRow.SettingsButton.isActive = self.activePage == "settings"
            ApplyShellTabStyle(self.frame.TabRow.SettingsButton, self.frame.TabRow.SettingsButton.isActive)
        end
    end

    addon.NewUIRoot.contentHost = self.contentHost

    if pageName == "news" and addon.NewUIRoot.RenderNews then
        return addon.NewUIRoot:RenderNews()
    end

    if pageName == "groups" and addon.NewUIRoot.RenderGroups then
        return addon.NewUIRoot:RenderGroups()
    end

    if pageName == "mytoons" and addon.NewUIRoot.RenderMyToons then
        return addon.NewUIRoot:RenderMyToons()
    end

    if pageName == "roster" and addon.NewUIRoot.RenderRoster then
        return addon.NewUIRoot:RenderRoster()
    end

    if pageName == "bis" and addon.NewUIRoot.RenderBIS then
        return addon.NewUIRoot:RenderBIS()
    end

    if pageName == "mythicplus" and addon.NewUIRoot.RenderMythicPlus then
        return addon.NewUIRoot:RenderMythicPlus()
    end

    if pageName == "raidbingo" and addon.NewUIRoot.RenderRaidBingo then
        return addon.NewUIRoot:RenderRaidBingo()
    end

    if pageName == "celebrate" and addon.NewUIRoot.RenderCelebrate then
        return addon.NewUIRoot:RenderCelebrate()
    end

    if pageName == "settings" and addon.NewUIRoot.RenderSettings then
        return addon.NewUIRoot:RenderSettings()
    end

    if addon.NewUIRoot.RenderHome then
        return addon.NewUIRoot:RenderHome()
    end

    return nil
end

function shell:Create(parent)
    local frame = CreateFrame("Frame", "GH3_NewUIPreviewFrame", UIParent, "BackdropTemplate")
    frame:SetFrameStrata("FULLSCREEN_DIALOG")
    frame:SetFrameLevel(180)
    frame:SetToplevel(true)
    frame:SetSize(BASE_SHELL_FRAME_WIDTH, BASE_SHELL_FRAME_HEIGHT)
    frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
    frame:SetMovable(true)
    frame:EnableMouse(true)
    frame:SetClampedToScreen(true)
    frame:Hide()
    frame._needsDeferredConfiguredSize = true
    self.activePage = self.activePage or "home"
    CreateShellBackdrop(frame)
    if frame.ShellBackgroundArt then
        frame.ShellBackgroundArt:SetFrameLevel(frame:GetFrameLevel() + 1)
    end
    if frame.ShellBorderArt then
        frame.ShellBorderArt:SetFrameLevel(frame:GetFrameLevel() + 8)
    end

    frame.TitleArea = CreateTitleArea(frame)
    frame.TitleArea:SetFrameLevel(frame:GetFrameLevel() + 12)
    if frame.TitleArea.OrnamentFrame then
        frame.TitleArea.OrnamentFrame:SetFrameStrata(frame.TitleArea:GetFrameStrata())
        frame.TitleArea.OrnamentFrame:SetFrameLevel(frame.TitleArea:GetFrameLevel() + 1)
    end
    frame.TabRow = CreateTabRow(frame)
    frame.TabRow:SetFrameLevel(frame:GetFrameLevel() + 11)

    frame.contentHost = CreateContentHost(frame)
    frame.contentHost:SetFrameLevel(frame:GetFrameLevel() + 6)
    self.contentHost = frame.contentHost
    self.frame = frame
    self.isDragging = false
    frame:HookScript("OnShow", function(shownFrame)
        if not shownFrame._needsDeferredConfiguredSize then
            return
        end

        shownFrame._needsDeferredConfiguredSize = false

        if self.frame == shownFrame then
            self:ApplyConfiguredSize()
            self:ApplyConfiguredTransparency()
        end
    end)
    self:ApplyConfiguredSize()
    self:ApplyConfiguredTransparency()

    return frame
end

function shell:RenderHome(snapshot)
    if not self.frame or not self.contentHost or not addon.NewUIRoot then
        return nil
    end

    return self:ShowPage("home", snapshot)
end

function addon:OpenNewUIPreview()
    if not addon.NewUIShell then
        return nil
    end

    local shell = addon.NewUIShell

    if shell.frame and shell.frame:IsShown() then
        shell.frame:Hide()
        return shell.frame
    end

    if not shell.frame then
        shell:Create(UIParent)
    end

    if shell.frame then
        shell.frame:Show()
        shell:ShowPage("home")
        return shell.frame
    end

    return nil
end

return shell