local AceConfig = LibStub("AceConfig-3.0")
local AceConfigDialog = LibStub("AceConfigDialog-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("CritMatic")
Critmatic = Critmatic or {}

function Critmatic:CreateOptionsTable()
    local Settings = LibStub("LibMatic-Settings-1.0", true)
    local notification_constructor = Critmatic:GetModule("notification_constructor", true)
    local args = {}

    local function alertStrings()
        return Critmatic.db.profile.alertNotificationFormat.strings
    end

    local function preview(formatKey, isDamage, isCrit, sound)
        return function()
            if notification_constructor then
                notification_constructor:formatConstructor(alertStrings()[formatKey], isDamage, isCrit, sound)
            end
        end
    end

    local function compactStyleToggle(field, order, name, desc)
        return {
            name = name,
            desc = desc,
            type = "toggle",
            order = order,
            set = function(_, newVal)
                local broker = Critmatic.db.profile.brokerSettings
                if newVal then
                    broker.compactNumbers = false
                    broker.compactInitials = false
                    broker.compactLabels = false
                    broker[field] = true
                else
                    broker[field] = false
                end
                if Critmatic.UpdateBroker then Critmatic.UpdateBroker() end
            end,
            get = function()
                return Critmatic.db.profile.brokerSettings[field]
            end,
        }
    end

    if Settings then
        local countUp = Settings:BuildCountUpControls({
            enabled = {
                get = function() return Critmatic.db.profile.alertNotificationFormat.global.countUpEnabled end,
                set = function(_, v) Critmatic.db.profile.alertNotificationFormat.global.countUpEnabled = v and true or false end,
            },
            duration = {
                get = function() return Critmatic.db.profile.alertNotificationFormat.global.countUpDuration end,
                set = function(_, v) Critmatic.db.profile.alertNotificationFormat.global.countUpDuration = v end,
            },
            hold = {
                get = function() return Critmatic.db.profile.alertNotificationFormat.global.countUpHold end,
                set = function(_, v) Critmatic.db.profile.alertNotificationFormat.global.countUpHold = v end,
            },
            startDelay = {
                get = function() return Critmatic.db.profile.alertNotificationFormat.global.startDelay end,
                set = function(_, v) Critmatic.db.profile.alertNotificationFormat.global.startDelay = v end,
            },
            names = {
                toggle = L["options_animate_alert_numbers"], toggleDesc = L["options_animate_alert_numbers_desc"],
                duration = "Animation Length", durationDesc = "How long the record number takes to count up, in seconds. Only used when Animate Alert Numbers is on.",
                hold = "Stay After Animation", holdDesc = "How long the alert stays on screen after the count-up finishes, in seconds, before it fades. Only used when Animate Alert Numbers is on.",
                startDelay = "Start Delay", startDelayDesc = "How long the alert stays on screen before fading, in seconds. Used when Animate Alert Numbers is off.",
            },
            toggleOrder = 1.90,
            durationOrder = 7,
            holdOrder = 9,
            startDelayOrder = 3,
            width = "300",
        })

        args.general_tab = Settings:BuildGeneralPage({
            name = L["options_general"],
            order = 1,
            currentAddon = "CritMatic",
            bind = { table = function() return Critmatic.db.profile.generalSettings end },
            toggles = {
                { key = "alertNotificationsEnabled", order = 2, name = L["options_show_alert_notifications"], desc = L["options_show_alert_notifications_desc"] },
                { key = "chatNotificationsEnabled", order = 3, name = L["options_show_chat_notifications"], desc = L["options_show_chat_notifications_desc"] },
                { key = "isChangeLogAutoPopUpEnabled", order = 4, name = L["options_show_change_log"], desc = L["options_show_change_log_desc"] },
                { key = "critsOnlyEnabled", order = 5, name = L["options_crits_only"], desc = L["options_crits_only_desc"] },
                { key = "showPreviousRecord", order = 6, name = L["options_show_previous_record"], desc = L["options_show_previous_record_desc"] },
                { key = "ignoreTrivialTargets", order = 7, name = L["options_ignore_trivial_targets"], desc = L["options_ignore_trivial_targets_desc"] },
            },
            extras = {
                critLogEnabled = {
                    name = L["options_show_crit_log"],
                    desc = L["options_show_crit_log_desc"],
                    type = "toggle",
                    order = 1,
                    set = function(_, newVal)
                        if newVal ~= Critmatic.db.profile.isCritLogFrameShown then
                            toggleCritMaticCritLog()
                        end
                    end,
                    get = function()
                        return Critmatic.db.profile.isCritLogFrameShown
                    end,
                },
                critLogLocked = {
                    name = L["options_lock_crit_log"],
                    desc = L["options_lock_crit_log_desc"],
                    type = "toggle",
                    order = 1.5,
                    set = function(_, newVal)
                        Critmatic.db.profile.critLogWidgetPos.lock = newVal
                    end,
                    get = function()
                        return Critmatic.db.profile.critLogWidgetPos.lock
                    end,
                },
                minimapIcon = {
                    name = L["options_show_minimap_icon"],
                    desc = L["options_show_minimap_icon_desc"],
                    type = "toggle",
                    order = 1.75,
                    set = function(_, newVal)
                        Critmatic.SetMinimapHidden(not newVal)
                    end,
                    get = function()
                        return not (Critmatic.db.profile.minimap and Critmatic.db.profile.minimap.hide)
                    end,
                },
                brokerHitFirst = {
                    name = L["options_broker_hit_first"],
                    desc = L["options_broker_hit_first_desc"],
                    type = "toggle",
                    order = 1.80,
                    set = function(_, newVal)
                        Critmatic.db.profile.brokerSettings.hitFirst = newVal and true or false
                        if Critmatic.UpdateBroker then Critmatic.UpdateBroker() end
                    end,
                    get = function()
                        return Critmatic.db.profile.brokerSettings.hitFirst
                    end,
                },
                brokerCompactNumbers = compactStyleToggle("compactNumbers", 1.82, L["options_broker_compact_numbers"], L["options_broker_compact_numbers_desc"]),
                brokerCompactInitials = compactStyleToggle("compactInitials", 1.84, L["options_broker_compact_initials"], L["options_broker_compact_initials_desc"]),
                brokerCompactLabels = compactStyleToggle("compactLabels", 1.86, L["options_broker_compact_labels"], L["options_broker_compact_labels_desc"]),
                animateAlertNumbers = countUp.toggle,
                recordThreshold = {
                    name = L["options_record_threshold"],
                    desc = L["options_record_threshold_desc"],
                    type = "range",
                    order = 8,
                    width = "full",
                    min = 0,
                    max = 100,
                    step = 5,
                    set = function(_, newVal)
                        Critmatic.db.profile.generalSettings.recordAnnounceThreshold = newVal
                    end,
                    get = function()
                        return Critmatic.db.profile.generalSettings.recordAnnounceThreshold or 0
                    end,
                },
            },
            support = {
                discordURL = "https://discord.gg/34JJyrnGGC",
                discordIcon = "Interface\\AddOns\\CritMatic\\Media\\Textures\\discord.tga",
                coffeeURL = "https://buymeacoffee.com/infiniteloopalchemist",
                coffeeIcon = "Interface\\AddOns\\CritMatic\\Media\\Textures\\bmc-logo.tga",
            },
            nav = {
                iconRoot = "Interface\\AddOns\\CritMatic\\Media\\Textures\\",
                factionIcons = false,
                extraLinks = {
                    { label = L["options_x_link"] or "Follow on X", url = "https://x.com/infiniteloopalc", icon = "x-logo.tga" },
                },
            },
        })

        local alertGlobals = Critmatic:AlertGeneralFragment()
        alertGlobals.countUpDuration = countUp.duration
        alertGlobals.countUpHold = countUp.hold
        alertGlobals.startDelay = countUp.startDelay

        args.alertFont_Tab = Settings:BuildAlertPage({
            order = 2,
            bind = { table = alertStrings },
            notificationTypes = {
                {
                    key = "critAlertNotificationFormat",
                    title = L["options_alert_chat_notification_format_crit"],
                    desc = L["options_alert_chat_notification_format_crit_desc"],
                    defaultFormat = "New %s Crit: %d!",
                    preview = preview("critAlertNotificationFormat", true, true, "soundCrit"),
                },
                {
                    key = "hitAlertNotificationFormat",
                    title = L["options_alert_chat_notification_format_hit"],
                    desc = L["options_alert_chat_notification_format_hit_desc"],
                    defaultFormat = "New %s Hit: %d!",
                    preview = preview("hitAlertNotificationFormat", true, false, "soundHit"),
                },
                {
                    key = "critHealAlertNotificationFormat",
                    title = L["options_alert_chat_notification_format_crit_heal"],
                    desc = L["options_alert_chat_notification_format_crit_heal_desc"],
                    defaultFormat = "New %s Crit Heal: %d!",
                    preview = preview("critHealAlertNotificationFormat", false, true, "soundCritHeal"),
                },
                {
                    key = "healAlertNotificationFormat",
                    title = L["options_alert_chat_notification_format_heal"],
                    desc = L["options_alert_chat_notification_format_heal_desc"],
                    defaultFormat = "New %s Heal: %d!",
                    preview = preview("healAlertNotificationFormat", false, false, "soundHeal"),
                },
            },
            globals = alertGlobals,
            font = Critmatic:AlertFontFragment(),
            messageExtras = Critmatic:AlertMessageExtras(),
            bounce = {
                get = function()
                    return Critmatic.db.profile.alertNotificationFormat.global.bounceStyle or "legacy"
                end,
                set = function(_, val)
                    Critmatic.db.profile.alertNotificationFormat.global.bounceStyle = val
                end,
            },
            position = {
                order = 11,
                get = function()
                    return Critmatic.db.profile.alertNotificationFormat.position.xPos,
                        Critmatic.db.profile.alertNotificationFormat.position.yPos
                end,
                set = function(x, y)
                    Critmatic.db.profile.alertNotificationFormat.position.xPos = x
                    Critmatic.db.profile.alertNotificationFormat.position.yPos = y
                end,
                default = function() return 50, 70 end,
                font = function()
                    local LSM = LibStub("LibSharedMedia-3.0", true)
                    local fs = Critmatic.db.profile.fontSettings
                    local path = (LSM and LSM:Fetch("font", fs.font)) or STANDARD_TEXT_FONT
                    return path, fs.fontSize, fs.fontOutline
                end,
                color = function()
                    return unpack(Critmatic.db.profile.fontSettings.fontColorCrit)
                end,
                close = function()
                    local frame = AceConfigDialog and AceConfigDialog.OpenFrames
                        and AceConfigDialog.OpenFrames["CritMaticOptions"]
                    if frame then frame:Hide() end
                end,
                reopen = function()
                    local frame = AceConfigDialog and AceConfigDialog.OpenFrames
                        and AceConfigDialog.OpenFrames["CritMaticOptions"]
                    if frame then frame:Show() end
                end,
            },
        })

        args.sound_tab = Settings:BuildSoundPage({
            name = L["options_sound_settings"],
            order = 3,
            bind = {
                table = function() return Critmatic.db.profile.soundSettings end,
                defaults = function() return Critmatic.db.defaults.profile.soundSettings end,
            },
            slots = {
                { key = "damageCrit", label = L["options_sound_crit"] },
                { key = "damageNormal", label = L["options_sound_hit"] },
                { key = "healCrit", label = L["options_sound_crit_heal"] },
                { key = "healNormal", label = L["options_sound_heal"] },
            },
            muteToggle = {
                key = "muteAllSounds",
                name = L["options_sound_mute_all"],
                desc = L["options_sound_mute_all_desc"],
            },
        })

        args.social_tab = Settings:BuildSocialPage({
            name = L["options_social"],
            order = 4,
            bind = { table = function() return Critmatic.db.profile.social end },
            channels = {
                { key = "canSendCritsToParty", name = L["options_social_send_crits_toParty"], desc = L["options_social_send_crits_toParty_desc"] },
                { key = "canSendCritsToRaid", name = L["options_social_send_crits_toRaid"], desc = L["options_social_send_crits_toRaid_desc"] },
                { key = "canSendCritsToGuild", name = L["options_social_send_crits_toGuild"], desc = L["options_social_send_crits_toGuild_desc"] },
                { key = "canSendCritsToBattleGrounds", name = L["options_social_send_crits_toBattleGrounds"], desc = L["options_social_send_crits_toBattleGrounds_desc"] },
            },
        })

        args.changeLog_tab = Settings:BuildChangeLogPage({
            name = L["options_change_log"],
            order = 5,
            profile = function() return Critmatic.db.profile.changeLogPopUp end,
        })
    end

    args.ignoredSpells_tab = Critmatic:IgnoredSpellsTab_Initialize()

    return {
        name = "CritMatic Options",
        type = "group",
        args = args,
    }
end

local settings = LibStub("LibMatic-Settings-1.0", true)
local blizzPanel, catID
if settings then
    blizzPanel, catID = settings:RegisterPanel({ appName = "CritMaticOptions", displayName = "CritMatic", options = Critmatic:CreateOptionsTable() })
else
    AceConfig:RegisterOptionsTable("CritMaticOptions", Critmatic:CreateOptionsTable())
    blizzPanel = AceConfigDialog:AddToBlizOptions("CritMaticOptions", "CritMatic")
end
Critmatic.settingsCategoryID = catID

if type(InterfaceOptionsList_DisplayPanel) == "function" then
    hooksecurefunc("InterfaceOptionsList_DisplayPanel", function(frame)
        if frame == blizzPanel then
        end
    end)
end
