local _AddonName, _EchoRaidTools = ...;
local _CombatTimer = _EchoRaidTools:NewModule("CombatTimer")

local LibSharedMedia = LibStub:GetLibrary ("LibSharedMedia-3.0")
local LibEditMode = LibStub('LibEditMode')

local FontArray
local getFontArray = function()
    if not FontArray then
        FontArray = {}
        local fonts = LibSharedMedia:HashTable("font")
        for name, fontPath in pairs (fonts) do
            table.insert(FontArray, {value = name, text = name, font = fontPath})
        end
        table.sort(FontArray, function (t1, t2) return t1.text < t2.text end)
        return FontArray
    else
        return FontArray
    end
end

local function OnLibSharedMediaRegistered(_, mediaType, key)
    if mediaType == "font" then
        FontArray = nil
    end
end
LibSharedMedia.RegisterCallback(_CombatTimer, "LibSharedMedia_Registered", OnLibSharedMediaRegistered)

local function formatTime(secs)
    local mins = floor(secs / 60)
    secs = secs % 60
    return format("%02.0f:%04.1f", mins, secs)
end

local function validateDefaultOptions(settings, defaultSettings)
    -- Set defaults if needed
    for key, value in pairs(defaultSettings) do
        if type(settings[key]) ~= type(value) then
            settings[key] = value
        elseif type(value) == "table" then
            validateDefaultOptions(settings[key], value)
        end
    end

    -- Remove old keys
    for key, _ in pairs(settings) do
        if defaultSettings[key] == nil then
            settings[key] = nil
        end
    end
    return settings
end

function _CombatTimer:ADDON_LOADED(addonName)
    if addonName ~= _AddonName then return end
    if _CombatTimer.initialized then return end

    if type(EchoRaidToolsDB.CombatTimer) ~= "table" then EchoRaidToolsDB.CombatTimer = {} end
    if type(EchoRaidToolsDB.CombatTimer.Enabled) ~= "boolean" then EchoRaidToolsDB.CombatTimer.Enabled = true end
    if type(EchoRaidToolsDB.CombatTimer.X) ~= "number" then EchoRaidToolsDB.CombatTimer.X = 100 end
    if type(EchoRaidToolsDB.CombatTimer.Y) ~= "number" then EchoRaidToolsDB.CombatTimer.Y = -100 end
    if type(EchoRaidToolsDB.CombatTimer.Font) ~= "string" then EchoRaidToolsDB.CombatTimer.Font = "Friz Quadrata TT" end
    local settings = EchoRaidToolsDB.CombatTimer

    local combatTimerFrame = CreateFrame("Frame", nil, UIParent)
    Mixin(combatTimerFrame, BackdropTemplateMixin)
    combatTimerFrame:SetBackdrop({
            bgFile = [[Interface/Buttons/WHITE8X8]],
            edgeFile = [[Interface/Buttons/WHITE8X8]],
            edgeSize = 1,
    })
    combatTimerFrame:SetBackdropColor(0, 0, 0, 0.5)
    combatTimerFrame:SetBackdropBorderColor(0, 0, 0, 1)
    combatTimerFrame:SetSize(100, 50)

    local combatTimerText = combatTimerFrame:CreateFontString(nil, "OVERLAY", "Number18Font")
    combatTimerText:SetPoint("CENTER", combatTimerFrame, "CENTER")

    local eventFrame = CreateFrame("Frame")
    eventFrame:SetScript("OnEvent", function(self, event, ...)
        if event == "ENCOUNTER_END" or event == "PLAYER_REGEN_ENABLED" then
            _CombatTimer.StopTimer(event)
        elseif event == "ENCOUNTER_START" or event == "PLAYER_REGEN_DISABLED" then
            _CombatTimer.StartTimer(event)
        end
    end)

    local startTime
    local running = false
    local isEncounter = false

    local currentElapsed = 0
    local function OnUpdate(self, elapsed)
        if running then
            currentElapsed = currentElapsed + elapsed
            if currentElapsed > 0.1 then
                currentElapsed = 0
                _CombatTimer.UpdateTimer(GetTime() - startTime)
            end
        end
    end
    function _CombatTimer.UpdateTimer(secs)
        combatTimerText:SetText(formatTime(secs))
    end
    function _CombatTimer.StopTimer(event)
        local encounterEndEvent = event == "ENCOUNTER_END"
        if running and
        (
            (isEncounter == encounterEndEvent)
            or
            (isEncounter and not IsEncounterInProgress())
        ) then
            running = false
            isEncounter = false
            eventFrame:SetScript("OnUpdate", nil)
        end
    end
    function _CombatTimer.StartTimer(event)
        if not running then
            running = true
            startTime = GetTime()
            currentElapsed = 0
            eventFrame:SetScript("OnUpdate", OnUpdate)
            isEncounter = event == "ENCOUNTER_START"
        end
    end
    _CombatTimer.UpdateTimer(0)
    local width, height = combatTimerText:GetStringWidth() + 6, combatTimerText:GetStringHeight() + 4
    combatTimerFrame:SetSize(width, height)


    function _CombatTimer.GetModuleEnabled()
        return settings.Enabled
    end

    function _CombatTimer.UpdateModuleState()
        if settings.Enabled then
            combatTimerFrame:Show()
            eventFrame:RegisterEvent("ENCOUNTER_END")
            eventFrame:RegisterEvent("ENCOUNTER_START")
            eventFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
            eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
            eventFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
        else
            combatTimerFrame:Hide()
            eventFrame:UnregisterEvent("ENCOUNTER_END")
            eventFrame:UnregisterEvent("ENCOUNTER_START")
            eventFrame:UnregisterEvent("PLAYER_REGEN_DISABLED")
            eventFrame:UnregisterEvent("PLAYER_REGEN_ENABLED")
            _CombatTimer.StopTimer()
        end
    end

    _CombatTimer.UpdateModuleState()

    function _CombatTimer.ToggleModuleEnabled()
        settings.Enabled = not settings.Enabled
        _CombatTimer.UpdateModuleState()
    end

    function _CombatTimer:GetNavigationButtons()
    end

    function _CombatTimer:GetConfig()
        if _EchoRaidTools.panels.CombatTimerModule then
            return _EchoRaidTools.panels.CombatTimerModule
        end

        --main panel creation
        local window = CreateFrame("FRAME", nil, _EchoRaidTools.panels.main, "EchoRaidToolsMainConfigWindow")
        window.Header.HeaderText:SetText("Combat Timer")
        window.Header.EnableModule.tooltip = "Enable/Disable the Combat Timer display"
        window.Header.EnableModule:SetChecked(_CombatTimer.GetModuleEnabled())
        window.Header.EnableModule:SetScript("OnClick", function(self)
            _CombatTimer.ToggleModuleEnabled()
            self:SetChecked(_CombatTimer.GetModuleEnabled())
        end)

        local panel = CreateFrame("FRAME", nil, window, "EchoRaidToolsMainConfigPanel")
        local helperText = panel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        helperText:SetPoint("TOPLEFT", panel, "TOPLEFT", 10, -10)
        helperText:SetText("You can find the Combat Timer in Edit Mode")
        local highlightTexture = combatTimerFrame:CreateTexture(nil, "BACKGROUND")
        highlightTexture:SetAllPoints(combatTimerFrame)
        highlightTexture:SetColorTexture(1, 1, 0, 0.5)
        highlightTexture:Hide()
        local editModeButton = CreateFrame("FRAME", nil, panel, "EchoRaidToolsConfig_Button")
        editModeButton:SetPoint("TOPLEFT", helperText, "BOTTOMLEFT", 0, -10)
        editModeButton:SetSize(200, 22)
        editModeButton.Button:SetText("Open Edit Mode")
        editModeButton.Button:SetScript("OnClick", function()
            ShowUIPanel(EditModeManagerFrame)
        end)

        local function onShowHandler()
            combatTimerFrame:EnableMouse(true)
            combatTimerFrame:SetMovable(true)
        end
        panel:SetScript("OnShow", onShowHandler)
        panel:SetScript("OnHide", function()
            combatTimerFrame:EnableMouse(false)
            combatTimerFrame:SetMovable(false)
        end)

        -- Call the show handler immediately since OnShow won't fire on initial creation
        onShowHandler()

        panel:SetPoint("TOPLEFT", window.Header, "BOTTOMLEFT")
        panel:SetPoint("BOTTOMRIGHT")
        local mainContainer = panel.ScrollFrame.ScrollingPanel
        _CombatTimer.controlParent = mainContainer
        _CombatTimer.mainWindow = window
        _CombatTimer.mainPanel = panel
        _CombatTimer.mainWindow.currentPanel = panel

        panel.ScrollFrame:SetVerticalScroll(0)
        local Resize = function() end
        panel:SetScript("OnSizeChanged", Resize)

        _EchoRaidTools.panels.CombatTimerModule = window

        local ScrollingPanel = CreateFrame("Frame", nil, mainContainer, "EchoRaidToolsMainConfigPanel")
        ScrollingPanel:SetAllPoints()
        ScrollingPanel:Show()

        return window
    end
    function _CombatTimer:GetButtonInfo()
        return "Combat Timer",
        nil,
        function()
            return _CombatTimer:GetConfig()
        end,
        _CombatTimer:GetNavigationButtons()
    end

    -- LibEditMode Stuffs
    local defaultSettings = {
        point = 'CENTER',
        font = 'Friz Quadrata TT',
        fontSize = 18,
        x = 100,
        y = -100,
        showBackground = true,
        showBorder = true,
    }

    local function onPositionChanged(frame, layoutName, point, x, y)
        EchoRaidToolsDB.CombatTimer[layoutName].point = point
        EchoRaidToolsDB.CombatTimer[layoutName].x = x
        EchoRaidToolsDB.CombatTimer[layoutName].y = y
    end

    local function setBackgroundSize()
        local width, height = combatTimerText:GetStringWidth() + 6, combatTimerText:GetStringHeight() + 4
        combatTimerFrame:SetSize(width, height)
    end

    local function updateCombatTimerBackground(showBackground, showBorder)
        if showBackground then
            combatTimerFrame:SetBackdropColor(0, 0, 0, 0.5)
        else
            combatTimerFrame:SetBackdropColor(0, 0, 0, 0)
        end
        if showBorder then
            combatTimerFrame:SetBackdropBorderColor(0, 0, 0, 1)
        else
            combatTimerFrame:SetBackdropBorderColor(0, 0, 0, 0)
        end
    end

    local function setCombatTimerFont(fontName, fontSize)
        if not fontName or not fontSize then return end -- can get called before settings are loaded in the callback? weird.
        local fontPath = LibSharedMedia:Fetch("font", fontName)
        combatTimerText:SetFont(fontPath, fontSize)
        setBackgroundSize()
    end

    LibEditMode:RegisterCallback('layout', function(layoutName)
        if not EchoRaidToolsDB.CombatTimer then
            EchoRaidToolsDB.CombatTimer = {}
        end
        EchoRaidToolsDB.CombatTimer[layoutName] = validateDefaultOptions(EchoRaidToolsDB.CombatTimer[layoutName] or {}, defaultSettings)


        combatTimerFrame:ClearAllPoints()
        combatTimerFrame:SetPoint(EchoRaidToolsDB.CombatTimer[layoutName].point, EchoRaidToolsDB.CombatTimer[layoutName].x, EchoRaidToolsDB.CombatTimer[layoutName].y)

        setCombatTimerFont(EchoRaidToolsDB.CombatTimer[layoutName].font, EchoRaidToolsDB.CombatTimer[layoutName].fontSize)
        updateCombatTimerBackground(EchoRaidToolsDB.CombatTimer[layoutName].showBackground, EchoRaidToolsDB.CombatTimer[layoutName].showBorder)
    end)

    LibEditMode:AddFrame(combatTimerFrame, onPositionChanged, defaultSettings, "Combat Timer - Echo Raid Tools")

    local function OnSettingsChanged(layoutName)
        setCombatTimerFont(EchoRaidToolsDB.CombatTimer[layoutName].font, EchoRaidToolsDB.CombatTimer[layoutName].fontSize)
        updateCombatTimerBackground(EchoRaidToolsDB.CombatTimer[layoutName].showBackground, EchoRaidToolsDB.CombatTimer[layoutName].showBorder)
    end

    LibEditMode:AddFrameSettings(combatTimerFrame, {
        {
            name = 'Font',
            kind = LibEditMode.SettingType.Dropdown,
            default = defaultSettings.font,
            values = getFontArray,
            get = function(layoutName)
                return EchoRaidToolsDB.CombatTimer[layoutName].font
            end,
            set = function(layoutName, value)
                EchoRaidToolsDB.CombatTimer[layoutName].font = value
                OnSettingsChanged(layoutName)
            end,
            height = 300, -- px
        },
        {
            name = 'Font Size',
            kind = LibEditMode.SettingType.Slider ,
            default = defaultSettings.fontSize,
            minValue = 5,
            maxValue = 50,
            get = function(layoutName)
                return EchoRaidToolsDB.CombatTimer[layoutName].fontSize
            end,
            set = function(layoutName, value)
                EchoRaidToolsDB.CombatTimer[layoutName].fontSize = value
                OnSettingsChanged(layoutName)
            end,
        },
        {
            name = 'Show Background',
            kind = LibEditMode.SettingType.Checkbox,
            default = defaultSettings.showBackground,
            get = function(layoutName)

                return EchoRaidToolsDB.CombatTimer[layoutName].showBackground
            end,
            set = function(layoutName, value)
                EchoRaidToolsDB.CombatTimer[layoutName].showBackground = value
                OnSettingsChanged(layoutName)
            end
        },
        {
            name = 'Show Border',
            kind = LibEditMode.SettingType.Checkbox,
            default = defaultSettings.showBorder,
            get = function(layoutName)
                return EchoRaidToolsDB.CombatTimer[layoutName].showBorder
            end,
            set = function(layoutName, value)
                EchoRaidToolsDB.CombatTimer[layoutName].showBorder = value
                OnSettingsChanged(layoutName)
            end,
        }
    })

    _CombatTimer.initialized = true
end


