-- Custom Countdown Sounds (Retail-only)
-- Main addon file: CustomCountdownSounds.lua
--
-- Data files (loaded BEFORE this file in the .toc):
--   raidbosses.lua        -> CCS_RaidBosses  (table of {text=..., bold=...})
--   profile_*.lua         -> CCS_Profile_<KeyCapitalized> (compressed string)

local addonName = ...
local LSM = LibStub("LibSharedMedia-3.0")

--------------------------------------------------
-- Constants
--------------------------------------------------
local CATEGORY_NAME    = "Custom Countdown Sounds"
local COPY_PLACEHOLDER = "|cffFFD100Click a profile button above to load an import string.|r"

--------------------------------------------------
-- Forward declarations
--------------------------------------------------
local InfoFrame
local CopyFrame
local currentKey
local ShowCopyFrame     -- referenced before definition
local OpenProfileByKey  -- referenced before definition
local CCS_CategoryID    -- numeric id for Settings.OpenToCategory()

--------------------------------------------------
-- Sound registration
--------------------------------------------------
local basePath = "Interface\\AddOns\\" .. addonName .. "\\sounds\\"

local sounds = {
    "2s","3s","4s","5s","6s","7s","8s","9s","10s","11s","12s","13s",
    "break","breath","burn","dot","marked","move","out","pools","soak","spread","targeted",
    "spikes","rune","miasma",
    "avengers_shield","despotic_command","execution_sentence",
    "light_quill","void_quill","lightvoid_dive","rift_madness","shattering_twilight",
}

for _, sound in ipairs(sounds) do
    LSM:Register("sound", "CCS: " .. sound, basePath .. sound .. ".ogg")
end

--------------------------------------------------
-- Info Frame (spell reference) - floating popup
--------------------------------------------------

-- FontString pool to avoid leaking objects on every PopulateFrame call.
local fsPool = {}

local function AcquireFontString(parent)
    for i = #fsPool, 1, -1 do
        local fs = fsPool[i]
        if fs:GetParent() == parent then
            table.remove(fsPool, i)
            fs:Show()
            return fs
        end
    end
    return parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
end

local function ReleaseFontString(fs)
    fs:Hide()
    fs:SetText("")
    fsPool[#fsPool + 1] = fs
end

local activeFontStrings = {}

local function ClearInfoFrame()
    for i = #activeFontStrings, 1, -1 do
        ReleaseFontString(activeFontStrings[i])
        activeFontStrings[i] = nil
    end
end

local function PopulateInfoFrame(data)
    ClearInfoFrame()

    local yOffset    = -30
    local contentH   = 30  -- top padding

    for _, entry in ipairs(data) do
        local fs = AcquireFontString(InfoFrame)
        fs:SetPoint("TOPLEFT", InfoFrame, "TOPLEFT", 20, yOffset)
        fs:SetWidth(InfoFrame:GetWidth() - 40)
        fs:SetJustifyH("LEFT")
        fs:SetJustifyV("TOP")
        fs:SetWordWrap(true)
        fs:SetFontObject(entry.bold and "GameFontHighlightLarge" or "GameFontNormal")
        fs:SetText(entry.text or "")

        local h = fs:GetStringHeight()
        yOffset   = yOffset   - h - 3
        contentH  = contentH  + h + 3

        activeFontStrings[#activeFontStrings + 1] = fs
    end

    InfoFrame:SetHeight(contentH + 20)  -- bottom padding
end

local function ShowInfo(data, key)
    if InCombatLockdown() then
        print("|cffff5555CCS:|r Cannot open info window during combat.")
        return
    end

    currentKey = key

    if not InfoFrame then
        InfoFrame = CreateFrame("Frame", addonName .. "_InfoFrame", UIParent, "BackdropTemplate")
        InfoFrame:SetSize(320, 750)
        InfoFrame:SetPoint("LEFT")
        InfoFrame:SetMovable(true)
        InfoFrame:EnableMouse(true)
        InfoFrame:RegisterForDrag("LeftButton")
        InfoFrame:SetScript("OnDragStart", InfoFrame.StartMoving)
        InfoFrame:SetScript("OnDragStop",  InfoFrame.StopMovingOrSizing)
        InfoFrame:SetBackdrop({
            bgFile   = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile     = true,
            tileSize = 8,
            edgeSize = 12,
            insets   = { left=2, right=2, top=2, bottom=2 },
        })
        InfoFrame:SetBackdropColor(0, 0, 0, 0.6)

        local close = CreateFrame("Button", nil, InfoFrame, "UIPanelCloseButton")
        close:SetPoint("TOPRIGHT", -4, -4)

        local profileBtn = CreateFrame("Button", nil, InfoFrame, "UIPanelButtonTemplate")
        profileBtn:SetSize(90, 22)
        profileBtn:SetPoint("TOPLEFT", 12, -6)
        profileBtn:SetText("Profile")
        profileBtn:SetScript("OnClick", function()
            if not currentKey then return end
            OpenProfileByKey(currentKey)
        end)
    end

    PopulateInfoFrame(data)
    InfoFrame:Show()
end

--------------------------------------------------
-- Copy Frame (BigWigs import) - floating popup
--------------------------------------------------
ShowCopyFrame = function(text)
    if InCombatLockdown() then
        print("|cffff5555CCS:|r Cannot open profile window during combat.")
        return
    end

    if not CopyFrame then
        CopyFrame = CreateFrame("Frame", addonName .. "_CopyFrame", UIParent, "BackdropTemplate")
        CopyFrame:SetSize(520, 240)
        CopyFrame:SetPoint("TOP")
        CopyFrame:SetFrameStrata("DIALOG")
        CopyFrame:SetMovable(true)
        CopyFrame:EnableMouse(true)
        CopyFrame:RegisterForDrag("LeftButton")
        CopyFrame:SetScript("OnDragStart", CopyFrame.StartMoving)
        CopyFrame:SetScript("OnDragStop",  CopyFrame.StopMovingOrSizing)
        CopyFrame:SetBackdrop({
            bgFile   = "Interface\\Buttons\\WHITE8x8",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile     = true,
            tileSize = 8,
            edgeSize = 12,
            insets   = { left=2, right=2, top=2, bottom=2 },
        })
        CopyFrame:SetBackdropColor(0, 0, 0, 0.6)

        local close = CreateFrame("Button", nil, CopyFrame, "UIPanelCloseButton")
        close:SetPoint("TOPRIGHT", -4, -4)

        local instructions = CopyFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        instructions:SetPoint("TOP", 0, -20)
        instructions:SetWidth(480)
        instructions:SetJustifyH("CENTER")
        instructions:SetWordWrap(true)
        instructions:SetText(
            "Copy this text and paste it into the import box under\n" ..
            "BigWigs > Raid Bosses > <Relevant Raid> > Share"
        )

        local editBox = CreateFrame("EditBox", nil, CopyFrame)
        editBox:SetMultiLine(true)
        editBox:SetFontObject("GameFontHighlight")
        editBox:SetWidth(480)
        editBox:SetHeight(120)
        editBox:SetPoint("TOP", instructions, "BOTTOM", 0, -16)
        editBox:SetAutoFocus(false)
        editBox:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
        editBox:SetScript("OnEditFocusGained", function(self) self:HighlightText() end)
        editBox:SetScript("OnChar", function(self) self:ClearFocus() end)

        CopyFrame.editBox = editBox
    end

    CopyFrame.editBox:SetText(text or "")
    CopyFrame.editBox:SetCursorPosition(0)
    CopyFrame.editBox:HighlightText()
    CopyFrame:Raise()
    CopyFrame:Show()
end

--------------------------------------------------
-- Settings Panel UI helpers
--------------------------------------------------

-- Build a plain-text version of a data table for the non-interactive info box.
-- Preserves WoW color codes so the text stays readable.
local function BuildInfoTextString(data)
    if type(data) ~= "table" then return nil end
    local out = {}
    for _, entry in ipairs(data) do
        local t = entry.text or ""
        if entry.bold then
            -- Wrap headers in a bright white highlight
            t = "|cffffffff" .. t .. "|r"
        else
            t = "  " .. t
        end
        out[#out + 1] = t
    end
    return table.concat(out, "\n")
end

-- Scrollable text area.
--   allowSelection = true  -> click to select/copy (import strings)
--   allowSelection = false -> non-interactive display (raid boss info)
local function CreateScrollableTextBox(parent, width, height, allowSelection)
    local scroll = CreateFrame("ScrollFrame", nil, parent, "UIPanelScrollFrameTemplate")
    scroll:SetSize(width, height)

    if scroll.ScrollBar then
        scroll.ScrollBar:ClearAllPoints()
        scroll.ScrollBar:SetPoint("TOPRIGHT",    scroll, "TOPRIGHT",    -6, -16)
        scroll.ScrollBar:SetPoint("BOTTOMRIGHT", scroll, "BOTTOMRIGHT", -6,  16)
    end

    local editBox = CreateFrame("EditBox", nil, scroll)
    editBox:SetMultiLine(true)
    editBox:SetFontObject("GameFontHighlight")
    editBox:SetAutoFocus(false)
    editBox:EnableMouse(allowSelection)
    editBox:SetTextInsets(8, 8, 8, 8)
    editBox:SetWidth(width - 42)
    editBox:SetHeight(2000)
    editBox:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
    editBox:SetScript("OnTextChanged", function(self)
        scroll:UpdateScrollChildRect()
    end)

    if allowSelection then
        editBox:SetScript("OnEditFocusGained", function(self) self:HighlightText() end)
        editBox:SetScript("OnChar",            function(self) self:ClearFocus() end)
    else
        -- Pass wheel events up to the scrollframe when not interactive
        scroll:EnableMouseWheel(true)
        scroll:SetScript("OnMouseWheel", function(self, delta)
            local step = 30
            self:SetVerticalScroll(math.max(self:GetVerticalScroll() - delta * step, 0))
        end)
    end

    scroll:SetScrollChild(editBox)
    return scroll, editBox
end

local function CreateSectionFrame(parent, titleText, width, height)
    local f = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    f:SetSize(width, height)
    f:SetBackdrop({
        bgFile   = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile     = true,
        tileSize = 8,
        edgeSize = 12,
        insets   = { left=3, right=3, top=3, bottom=3 },
    })
    f:SetBackdropColor(0, 0, 0, 0.35)

    local title = f:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    title:SetPoint("TOPLEFT", 10, -8)
    title:SetText(titleText)

    return f, title
end

--------------------------------------------------
-- Profile helpers
--------------------------------------------------
local function GetProfileTextByKey(key)
    if not key or key == "" then return nil end
    -- Capitalise only the first character: "queldanas" -> "Queldanas"
    local var = "CCS_Profile_" .. (key:sub(1,1):upper() .. key:sub(2))
    return _G[var]
end

OpenProfileByKey = function(key)
    if InCombatLockdown() then
        print("|cffff5555CCS:|r Cannot open profile window during combat.")
        return
    end
    if not key or key == "" then return end

    local profileText = GetProfileTextByKey(key)
    if profileText then
        ShowCopyFrame(profileText)
    else
        local var = "CCS_Profile_" .. (key:sub(1,1):upper() .. key:sub(2))
        print("|cffff5555CCS error:|r No profile found for '" .. key .. "' (expected global: " .. var .. ")")
    end
end

--------------------------------------------------
-- Settings panel
--------------------------------------------------
local function CreateCCSOptionsPanel()
    local panel = CreateFrame("Frame", addonName .. "_OptionsPanel", UIParent)

    local title = panel:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
    title:SetPoint("TOP", 0, -16)
    title:SetText(CATEGORY_NAME)

    -- Instructions box
    local instBox, instBoxTitle = CreateSectionFrame(panel, "Instructions", 680, 155)
    instBox:SetPoint("TOP", title, "BOTTOM", 0, -12)

    local inst = instBox:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    inst:SetPoint("TOPLEFT",  instBoxTitle, "BOTTOMLEFT",  0,   -8)
    inst:SetPoint("TOPRIGHT", instBox,      "TOPRIGHT",   -18, -32)
    inst:SetJustifyH("LEFT")
    inst:SetJustifyV("TOP")
    inst:SetWordWrap(true)
    inst:SetText(
        "This addon uses BigWigs profiles to assign suggested spell/sound pairings.\n" ..
        "The Raid boss info panel shows what sound file is used with which private aura in the BigWigs profile.\n" ..
        "If timers are off, please comment on CurseForge and I will update them.\n" ..
        "\n" ..
        "You can also add custom timers using the 'CCS 2s–12s' sound files under '|cFFFF4040Private Aura Sounds|r' in BigWigs.\n" ..
        "\n" ..
        "|cffFFD100Import instructions:|r\n" ..
        "Click a '<Raid> profile' button on the right and copy the text below.\n" ..
        "Open |cFF40FF40BigWigs|r > |cffFFD100Raid Bosses|r > |cffFFD100<Relevant Raid>|r, click the red |cFFFF4040Share|r button, paste your profile string.\n"
    )

    -- Left: Raid boss info (read-only)
    local leftBox, leftTitle = CreateSectionFrame(panel, "Raid boss info", 320, 360)
    leftBox:SetPoint("TOPLEFT", instBox, "BOTTOMLEFT", 0, -14)

    local infoScroll, infoBox = CreateScrollableTextBox(leftBox, 308, 300, false)
    infoScroll:SetPoint("TOPLEFT", leftTitle, "BOTTOMLEFT", 0, -8)

    -- Right: Profiles + embedded copy field
    local rightBox, rightTitle = CreateSectionFrame(panel, "Profiles", 340, 360)
    rightBox:SetPoint("TOPRIGHT", instBox, "BOTTOMRIGHT", -12, -14)

    local hint = rightBox:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    hint:SetPoint("TOPLEFT",  rightTitle, "BOTTOMLEFT",  0,   -8)
    hint:SetPoint("TOPRIGHT", rightBox,   "TOPRIGHT",   -18, -32)
    hint:SetJustifyH("LEFT")
    hint:SetWordWrap(true)
    hint:SetText("Click a button, then copy the import string below.")

    -- Profile buttons
    local profiles = {
        { key = "queldanas", label = "March on Quel'Danas" },
        { key = "dreamrift", label = "The Dreamrift"       },
        { key = "voidspire", label = "The Voidspire"       },
        -- Future raids:
        -- { key = "raidtwo",   label = "Open Raid Two Profile" },
    }

    local lastBtn
    for _, p in ipairs(profiles) do
        local btn = CreateFrame("Button", nil, rightBox, "UIPanelButtonTemplate")
        btn:SetSize(300, 21)
        btn:SetPoint("TOPLEFT", lastBtn and lastBtn or hint, lastBtn and "BOTTOMLEFT" or "BOTTOMLEFT", 0, lastBtn and -10 or -12)
        btn:SetText(p.label or p.key)
        btn:SetScript("OnClick", function()
            if InCombatLockdown() then
                print("|cffff5555CCS:|r Cannot change profile during combat.")
                return
            end
            local profileText = GetProfileTextByKey(p.key)
            if profileText then
                if rightBox.copyEditBox then
                    rightBox.copyEditBox:SetText(profileText)
                    rightBox.copyEditBox:SetCursorPosition(0)
                    rightBox.copyEditBox:HighlightText()
                end
            else
                print("|cffff5555CCS error:|r No profile found for '" .. (p.key or "?") .. "'")
            end
        end)
        lastBtn = btn
    end

    -- Embedded copy box
    local copyLabel = rightBox:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    copyLabel:SetText("|cFFFFD100Import string (Ctrl+C to copy):|r")

    local copyScroll, copyEditBox = CreateScrollableTextBox(rightBox, 308, 120, true)
    copyScroll:SetPoint("BOTTOMLEFT", rightBox, "BOTTOMLEFT", 10, 70)
    copyLabel:SetPoint("BOTTOMLEFT",  copyScroll, "TOPLEFT",   0,  8)

    rightBox.copyEditBox = copyEditBox
    copyEditBox:SetText(COPY_PLACEHOLDER)
    copyEditBox:SetCursorPosition(0)

    -- Reset import box on hide
    panel:SetScript("OnHide", function()
        copyEditBox:SetText(COPY_PLACEHOLDER)
        copyEditBox:ClearFocus()
        copyEditBox:SetCursorPosition(0)
    end)

    -- Populate raid boss info
    local bossData = CCS_RaidBosses
    infoBox:SetText(bossData and BuildInfoTextString(bossData) or "No data found (expected: CCS_RaidBosses).")
    infoBox:SetCursorPosition(0)

    return panel
end

local function RegisterOptionsPanelRetail(panel)
    local category = Settings.RegisterCanvasLayoutCategory(panel, CATEGORY_NAME)
    Settings.RegisterAddOnCategory(category)

    if type(category) == "table" then
        if type(category.GetID) == "function" then
            CCS_CategoryID = category:GetID()
        elseif type(category.ID) == "number" then
            CCS_CategoryID = category.ID
        end
    end
end

local function OpenCCSOptions()
    if not CCS_CategoryID then
        print("|cffff5555CCS:|r Options category not registered yet.")
        return
    end
    Settings.OpenToCategory(CCS_CategoryID)
end

--------------------------------------------------
-- Slash commands
-- /ccs                  -> open settings page
-- /ccs info             -> open raid boss info floating window
-- /ccs profile <key>    -> open profile copy popup
--------------------------------------------------
SLASH_CCS1 = "/ccs"

SlashCmdList["CCS"] = function(msg)
    local cmd, arg = msg:match("^(%S*)%s*(.-)%s*$")
    cmd = (cmd or ""):lower()

    if cmd == "" then
        OpenCCSOptions()

    elseif cmd == "info" then
        local data = CCS_RaidBosses
        if not data then
            print("|cffff5555CCS error:|r Raid boss data not loaded (expected: CCS_RaidBosses).")
            return
        end
        -- Show info; currentKey will be nil until user picks a raid via InfoFrame's Profile button.
        ShowInfo(data, currentKey)

    elseif cmd == "profile" then
        local key = (arg or ""):lower()
        if key == "" then
            print("|cffff5555CCS usage:|r /ccs profile <key>  (e.g. queldanas, dreamrift, voidspire)")
            return
        end
        OpenProfileByKey(key)

    else
        print("|cffff5555CCS:|r Unknown command. Use /ccs, /ccs info, or /ccs profile <key>.")
    end
end

--------------------------------------------------
-- Init
--------------------------------------------------
local initFrame = CreateFrame("Frame")
initFrame:RegisterEvent("ADDON_LOADED")
initFrame:SetScript("OnEvent", function(self, _, name)
    if name ~= addonName then return end
    RegisterOptionsPanelRetail(CreateCCSOptionsPanel())
    self:UnregisterEvent("ADDON_LOADED")
end)