local addonName, SinsToolkit = ...

SinsToolkit.UI = SinsToolkit.UI or {}
SinsToolkit.UI.Pages = SinsToolkit.UI.Pages or {}

local PageBase = SinsToolkit.UI.Pages.Base or {}
local Helpers = SinsToolkit.UI.Pages.Helpers or {}
local Page = {}
setmetatable(Page, { __index = PageBase })
SinsToolkit.UI.Pages.Profiles = Page
Page.density = Helpers.GetDefaultDensity and Helpers.GetDefaultDensity() or "compact"

local UNKNOWN_CLASS = "Unknown Class"
local UNKNOWN_SPEC = "Unknown Spec"

StaticPopupDialogs["SINS_TOOLKIT_PROFILE_EXPORT"] = {
    text = "%s",
    button1 = CLOSE,
    hasEditBox = true,
    editBoxWidth = 360,
    OnShow = function(self, data)
        local editBox = self.EditBox or self.editBox
        if editBox then
            editBox:SetMaxLetters(0)
            editBox:SetText((type(data) == "table" and data.text) or "")
            editBox:HighlightText()
            editBox:SetFocus()
        end
    end,
    timeout = 0,
    whileDead = true,
    hideOnEscape = true,
    preferredIndex = 3,
}

local function EscapeKey(value)
    return tostring(value or ""):gsub("[^%w_%-]", "_")
end

local function GetClassColor(classToken)
    local color = classToken and RAID_CLASS_COLORS and RAID_CLASS_COLORS[classToken]
    if color then
        return color.r or 1, color.g or 1, color.b or 1
    end
    return 0.72, 0.72, 0.76
end

local function WrapClassColor(text, classToken)
    local r, g, b = GetClassColor(classToken)
    return ("|cff%02x%02x%02x%s|r"):format(math.floor(r * 255), math.floor(g * 255), math.floor(b * 255), text or UNKNOWN_CLASS)
end

local function NormalizeBackup(backup)
    local character = backup.character or "Unknown Character"
    local realm = backup.realm or ""
    local className = backup.className or UNKNOWN_CLASS
    local classToken = backup.classToken
    local specName = backup.specName or UNKNOWN_SPEC
    return {
        id = backup.id,
        name = backup.name or "Backup",
        character = character,
        realm = realm,
        characterKey = backup.characterKey or (realm ~= "" and (character .. "-" .. realm) or character),
        className = className,
        classToken = classToken,
        classKey = classToken or className,
        specName = specName,
        specKey = specName,
        createdAt = backup.createdAt or "Unknown date",
        createdAtEpoch = backup.createdAtEpoch or 0,
    }
end

local function BuildBackupGroups(backups)
    local classOrder, classMap = {}, {}
    local byID = {}
    for _, backup in ipairs(backups or {}) do
        local meta = NormalizeBackup(backup)
        byID[meta.id] = meta
        local classGroup = classMap[meta.classKey]
        if not classGroup then
            classGroup = {
                key = meta.classKey,
                name = meta.className,
                token = meta.classToken,
                specs = {},
                specOrder = {},
                count = 0,
            }
            classMap[meta.classKey] = classGroup
            classOrder[#classOrder + 1] = classGroup
        end

        local specGroup = classGroup.specs[meta.specKey]
        if not specGroup then
            specGroup = { key = meta.specKey, name = meta.specName, backups = {}, count = 0 }
            classGroup.specs[meta.specKey] = specGroup
            classGroup.specOrder[#classGroup.specOrder + 1] = specGroup
        end

        specGroup.backups[#specGroup.backups + 1] = meta
        specGroup.count = specGroup.count + 1
        classGroup.count = classGroup.count + 1
    end

    table.sort(classOrder, function(a, b)
        if a.name == UNKNOWN_CLASS then return false end
        if b.name == UNKNOWN_CLASS then return true end
        return a.name < b.name
    end)
    for _, classGroup in ipairs(classOrder) do
        table.sort(classGroup.specOrder, function(a, b)
            if a.name == UNKNOWN_SPEC then return false end
            if b.name == UNKNOWN_SPEC then return true end
            return a.name < b.name
        end)
    end
    return classOrder, byID
end

function Page:Create(CreateScrollablePage, Window, CreateWrappedText)
    local Theme = Helpers.GetTheme and Helpers.GetTheme()
    local profilesPage, content = CreateScrollablePage("Profiles")
    Helpers.CreatePageIntro(content, Window, "Profile Vault", "Save and restore character setup backups. Backups include action bars, account macros, character macros, keybinds, character name, realm, class, spec, backup date, and your custom backup name. Restore and delete actions require confirmation.", CreateWrappedText, 720)

    local createCard = Helpers.CreatePageCard(content, "Create Backup", 704, 112)
    createCard:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -92)
    Helpers.SetCardDescription(createCard, "Name this backup before saving your current action bars, macros, and keybinds.")

    local pBackupNameInput = CreateFrame("EditBox", nil, createCard, "InputBoxTemplate")
    pBackupNameInput:SetSize(220, 24)
    pBackupNameInput:SetPoint("TOPLEFT", createCard, "TOPLEFT", 18, -64)
    pBackupNameInput:SetAutoFocus(false)
    Window:SetTooltip(pBackupNameInput, "Backup Name", "Name this backup before saving your current action bars, macros, and keybinds.")

    local inputLabel = createCard:CreateFontString(nil, "OVERLAY", Theme and Theme.GetFont and Theme.GetFont("label") or "GameFontNormalSmall")
    inputLabel:SetPoint("BOTTOMLEFT", pBackupNameInput, "TOPLEFT", 0, 4)
    inputLabel:SetText("Backup Name")
    if Theme and Theme.ApplyLabelFont then Theme.ApplyLabelFont(inputLabel) end

    local pBtnCreate = Window:CreateButton(createCard, "Create Backup", 160, 30, function()
        if not SinsToolkit.ProfileVault then return end
        local name = pBackupNameInput:GetText()
        local backup = SinsToolkit.ProfileVault:CreateBackup(name)
        Window.selectedProfileVaultBackup = backup.id
        print("|cff9b59b6[Sin's Toolkit: QOL]|r Profile backup saved: " .. backup.name)
        if Window.RefreshProfilesPage then Window:RefreshProfilesPage() end
    end, "Saves this character's action bars, account macros, character macros, and keybinds into Profile Vault.")
    pBtnCreate:SetPoint("LEFT", pBackupNameInput, "RIGHT", 14, 0)

    local listCard = Helpers.ClearCardBody(Helpers.CreatePageCard(content, "Saved Backups", 386, 334))
    listCard:SetPoint("TOPLEFT", createCard, "BOTTOMLEFT", 0, -14)

    local pBackupList = CreateFrame("Frame", nil, listCard, "BackdropTemplate")
    pBackupList:SetSize(350, 270)
    pBackupList:SetPoint("TOPLEFT", listCard, "TOPLEFT", 18, -46)
    Helpers.ApplyListBackdrop(pBackupList, 0.1, 0.1, 0.1, 0.8, 0.4, 0.4, 0.4, 1)

    local pScrollFrame = CreateFrame("ScrollFrame", nil, pBackupList, "UIPanelScrollFrameTemplate")
    pScrollFrame:SetPoint("TOPLEFT", 4, -4)
    pScrollFrame:SetPoint("BOTTOMRIGHT", -26, 4)
    local pScrollChild = CreateFrame("Frame", nil, pScrollFrame)
    pScrollChild:SetSize(318, 1)
    pScrollFrame:SetScrollChild(pScrollChild)

    local detailsCard = Helpers.ClearCardBody(Helpers.CreatePageCard(content, "Backup Details", 304, 334))
    detailsCard:SetPoint("TOPLEFT", listCard, "TOPRIGHT", 14, 0)

    local pSummaryDetails = detailsCard:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    pSummaryDetails:SetPoint("TOPLEFT", detailsCard, "TOPLEFT", 18, -46)
    pSummaryDetails:SetWidth(268)
    pSummaryDetails:SetJustifyH("LEFT")
    pSummaryDetails:SetJustifyV("TOP")
    pSummaryDetails:SetText("No saved backups yet. Create a backup to store this character's current setup.")
    if Theme and Theme.ApplyStatusText then Theme.ApplyStatusText(pSummaryDetails) end

    local pBtnRestore = Window:CreateButton(detailsCard, "Restore Profile", 128, 28, function()
        if not SinsToolkit.ProfileVault or not Window.selectedProfileVaultBackup then return end
        SinsToolkit.ProfileVault:ConfirmRestoreBackup(Window.selectedProfileVaultBackup, function(ok, message)
            print("|cff9b59b6[Sin's Toolkit: QOL]|r " .. (message or (ok and "Profile restored." or "Profile restore failed.")))
        end)
    end, "Applies the selected backup to the current character after confirmation. This can replace action bars, macros, and keybindings.")
    pBtnRestore:SetPoint("BOTTOMLEFT", detailsCard, "BOTTOMLEFT", 18, 18)

    local pBtnDelete = Window:CreateButton(detailsCard, "Delete Profile", 128, 28, function()
        if not SinsToolkit.ProfileVault or not Window.selectedProfileVaultBackup then return end
        SinsToolkit.ProfileVault:ConfirmDeleteBackup(Window.selectedProfileVaultBackup, function(ok, message)
            if ok then
                Window.selectedProfileVaultBackup = nil
                if Window.RefreshProfilesPage then Window:RefreshProfilesPage() end
            end
            print("|cff9b59b6[Sin's Toolkit: QOL]|r " .. (message or (ok and "Profile backup deleted." or "Profile backup delete failed.")))
        end)
    end, "Deletes the selected backup from Sin's Toolkit saved variables after confirmation.")
    pBtnDelete:SetPoint("LEFT", pBtnRestore, "RIGHT", 10, 0)

    local pBtnExport = Window:CreateButton(detailsCard, "Export Backup", 128, 28, function()
        if not SinsToolkit.ProfileVault or not Window.selectedProfileVaultBackup then return end
        local text, message = SinsToolkit.ProfileVault:ExportBackup(Window.selectedProfileVaultBackup)
        if text and StaticPopup_Show then
            StaticPopup_Show("SINS_TOOLKIT_PROFILE_EXPORT", "Copy Profile Vault Export", nil, { text = text })
        else
            print("|cff9b59b6[Sin's Toolkit: QOL]|r " .. (message or "Profile backup export failed."))
        end
    end, "Opens a copyable text export for the selected backup.")
    pBtnExport:SetPoint("BOTTOMLEFT", pBtnRestore, "TOPLEFT", 0, 8)

    local importCard = Helpers.ClearCardBody(Helpers.CreatePageCard(content, "Import Backup", 704, 130))
    importCard:SetPoint("TOPLEFT", listCard, "BOTTOMLEFT", 0, -14)
    Helpers.SetCardDescription(importCard, "Paste a Sin's Toolkit Profile Vault export. Imported profiles are saved as normal backups before restore.")

    local importBox = CreateFrame("EditBox", nil, importCard, "InputBoxTemplate")
    importBox:SetSize(508, 24)
    importBox:SetPoint("TOPLEFT", importCard, "TOPLEFT", 18, -70)
    importBox:SetAutoFocus(false)
    importBox:SetMaxLetters(0)
    Window:SetTooltip(importBox, "Import Text", "Paste exported Profile Vault text here. Imports are validated before being saved.")

    local importButton = Window:CreateButton(importCard, "Import Backup", 150, 28, function()
        if not SinsToolkit.ProfileVault then return end
        local backup, message = SinsToolkit.ProfileVault:ImportBackup(importBox:GetText())
        if backup then
            Window.selectedProfileVaultBackup = backup.id
            importBox:SetText("")
            print("|cff9b59b6[Sin's Toolkit: QOL]|r Imported profile backup: " .. (backup.name or "Imported Backup"))
            if Window.RefreshProfilesPage then Window:RefreshProfilesPage() end
        else
            print("|cff9b59b6[Sin's Toolkit: QOL]|r " .. (message or "Profile backup import failed."))
        end
    end, "Validates pasted text and saves it as a normal Profile Vault backup.")
    importButton:SetPoint("LEFT", importBox, "RIGHT", 14, 0)

    local profileButtons = {}
    function Window:RefreshProfilesPage()
        for _, b in ipairs(profileButtons) do b:Hide() end
        if not SinsToolkit.ProfileVault then return end
        local backups = SinsToolkit.ProfileVault:GetBackups()
        local groups, backupByID = BuildBackupGroups(backups)
        if listCard.title then
            listCard.title:SetText("Saved Backups (" .. #backups .. ")")
        end
        Window.profileVaultExpandedClasses = Window.profileVaultExpandedClasses or {}
        Window.profileVaultExpandedSpecs = Window.profileVaultExpandedSpecs or {}
        local y = -2
        local hasSelection = false
        local rowIndex = 0

        local function AddRow(rowType, key, label, indent, height, backupID, onClick)
            rowIndex = rowIndex + 1
            local b = profileButtons[rowIndex]
            if not b then
                b = CreateFrame("Button", nil, pScrollChild, "BackdropTemplate")
                b.text = b:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                b.text:SetJustifyH("LEFT")
                if Theme and Theme.ApplySmallBodyFont then Theme.ApplySmallBodyFont(b.text) end
                b:SetScript("OnClick", function(self)
                    if self.onClick then self.onClick(self) end
                end)
                profileButtons[rowIndex] = b
            end
            b:SetSize(318, height)
            b.backupID = backupID
            b.onClick = onClick
            b.text:ClearAllPoints()
            b.text:SetPoint("LEFT", 6 + (indent or 0), 0)
            b.text:SetPoint("RIGHT", -6, 0)
            b:SetPoint("TOPLEFT", 0, y)
            b.text:SetText(label)
            if rowType == "backup" and Window.selectedProfileVaultBackup == backupID then
                Helpers.ApplySelectionBackdrop(b)
                hasSelection = true
            elseif rowType == "class" then
                Helpers.ApplyListBackdrop(b, 0.16, 0.12, 0.22, 0.86, 0.34, 0.22, 0.44, 0.75)
            elseif rowType == "spec" then
                Helpers.ApplyListBackdrop(b, 0.12, 0.12, 0.16, 0.76, 0.24, 0.24, 0.30, 0.65)
            else
                b:SetBackdrop(nil)
            end
            b:Show()
            y = y - height - 3
            return b
        end

        if #backups > 0 then
            for _, classGroup in ipairs(groups) do
                local classKey = EscapeKey(classGroup.key)
                if Window.profileVaultExpandedClasses[classKey] == nil then
                    Window.profileVaultExpandedClasses[classKey] = true
                end
                local classOpen = Window.profileVaultExpandedClasses[classKey]
                AddRow("class", classKey, ("%s %s (%d)"):format(classOpen and "-" or "+", WrapClassColor(classGroup.name, classGroup.token), classGroup.count), 0, 24, nil, function()
                    Window.profileVaultExpandedClasses[classKey] = not Window.profileVaultExpandedClasses[classKey]
                    Window:RefreshProfilesPage()
                end)

                if classOpen then
                    for _, specGroup in ipairs(classGroup.specOrder) do
                        local specKey = classKey .. "::" .. EscapeKey(specGroup.key)
                        if Window.profileVaultExpandedSpecs[specKey] == nil then
                            Window.profileVaultExpandedSpecs[specKey] = true
                        end
                        local specOpen = Window.profileVaultExpandedSpecs[specKey]
                        AddRow("spec", specKey, ("%s %s (%d)"):format(specOpen and "-" or "+", specGroup.name, specGroup.count), 14, 23, nil, function()
                            Window.profileVaultExpandedSpecs[specKey] = not Window.profileVaultExpandedSpecs[specKey]
                            Window:RefreshProfilesPage()
                        end)

                        if specOpen then
                            for _, backup in ipairs(specGroup.backups) do
                                AddRow("backup", backup.id, ("%s - %s - %s"):format(backup.name, backup.characterKey, backup.createdAt), 28, 27, backup.id, function(self)
                                    Window.selectedProfileVaultBackup = self.backupID
                                    Window:RefreshProfilesPage()
                                end)
                            end
                        end
                    end
                end
            end
        end
        for i = rowIndex + 1, #profileButtons do
            profileButtons[i]:Hide()
            profileButtons[i].onClick = nil
            profileButtons[i].backupID = nil
        end
        if Window.selectedProfileVaultBackup and not backupByID[Window.selectedProfileVaultBackup] then
            Window.selectedProfileVaultBackup = nil
        end
        pScrollChild:SetHeight(math.max(1, -y))

        if Window.selectedProfileVaultBackup then
            pSummaryDetails:SetText(SinsToolkit.ProfileVault:GetRestoreSummary(Window.selectedProfileVaultBackup) or "No details available.")
            pBtnRestore:Enable()
            pBtnDelete:Enable()
            pBtnExport:Enable()
        elseif #backups == 0 then
            pSummaryDetails:SetText("No saved backups yet. Create a backup to store this character's current action bars, macros, and keybinds.")
            pBtnRestore:Disable()
            pBtnDelete:Disable()
            pBtnExport:Disable()
        else
            pSummaryDetails:SetText("Select a saved backup to view its details.")
            pBtnRestore:Disable()
            pBtnDelete:Disable()
            pBtnExport:Disable()
        end
    end
    profilesPage.OnShowCallback = function() Window:RefreshProfilesPage() end

    content:SetHeight(705)
    self.frame = profilesPage
    return profilesPage
end

Page:Register("Profiles")

return Page
