local notification_constructor = Critmatic:NewModule("notification_constructor")

local L = LibStub("AceLocale-3.0"):GetLocale("CritMatic")

function ResetAlertSettingsToDefault()
    Critmatic.db.profile.alertNotificationFormat.strings = CopyTable(Critmatic.db.defaults.profile.alertNotificationFormat.strings)
    Critmatic.db.profile.alertNotificationFormat.position = CopyTable(Critmatic.db.defaults.profile.alertNotificationFormat.position)
end
function ResetFontSettingsToDefault()
    Critmatic.db.profile.fontSettings = CopyTable(Critmatic.db.defaults.profile.fontSettings)
end
function notification_constructor:OnInitialize()

end

function notification_constructor:OnEnable()
end

function notification_constructor:formatConstructor(message, isDamage, isCrit, sound_string)
    local LSM = LibStub("LibSharedMedia-3.0")
    -- Define a local table with 15 different spell names
    local spellNames = {}
    local r, g, b
    if isDamage then
        spellNames = {
            "Fireball",
            "Shadow Bolt",
            "Chain Lightning",
            "Death Coil",
            "Starfire",
            "Eviscerate",
            "Mind Blast",
            "Heroic Strike",
            "Arcane Shot",
            "Blade Flurry",
            "Judgment",
            "Shadowflame",
            "Stormstrike",
            "Mutilate",
            "Hammer of Wrath"
        }
    else
        spellNames = {
            "Circle of Healing",
            "Rejuvenation",
            "Lay on Hands",
            "Renew",
            "Riptide",
            "Holy Light",
            "Lifebloom",
            "Healing Rain",
            "Soothing Mist",
            "Penance",
            "Wild Growth",
            "Prayer of Healing"
        }
    end

    local soundCrit = LSM:Fetch("sound", Critmatic.db.profile.soundSettings.damageCrit)
    local soundHit = LSM:Fetch("sound", Critmatic.db.profile.soundSettings.damageNormal)
    local soundCritHeal = LSM:Fetch("sound", Critmatic.db.profile.soundSettings.healCrit)
    local soundHeal = LSM:Fetch("sound", Critmatic.db.profile.soundSettings.healNormal)

    -- Select a random spell name
    local spellName = spellNames[math.random(#spellNames)]
    -- Generate a random number between 3000 and 8000 for amount
    local amount = math.random(500, 8000)
    -- The format string is user-editable, so guard against a bad specifier.
    local ok, result = pcall(string.format, message, spellName, amount)
    if not ok then
        result = tostring(spellName) .. " " .. tostring(amount)
    end
    if Critmatic.db.profile.alertNotificationFormat.global.isUpper then
        result = string.upper(result)
    end

    if isCrit then
        r, g, b = unpack(Critmatic.db.profile.fontSettings.fontColorCrit)
    else
        r, g, b = unpack(Critmatic.db.profile.fontSettings.fontColor)
    end
    Critmatic.MessageFrame:CreateMessage(result, r, g, b)
    if not Critmatic.db.profile.soundSettings.muteAllSounds then
        local snd
        if sound_string == "soundCrit" then
            snd = soundCrit
        elseif sound_string == "soundHit" then
            snd = soundHit
        elseif sound_string == "soundCritHeal" then
            snd = soundCritHeal
        elseif sound_string == "soundHeal" then
            snd = soundHeal
        end
        -- Route through the same overlay-guard defer real alerts use, so a
        -- preview fired during a loading screen/cinematic stays in sync.
        Critmatic:DeferAlertSound(snd)
    end
end

function Critmatic.PreviewCritAlert()
    if not (Critmatic.db and Critmatic.db.profile) then return end
    local nc = Critmatic:GetModule("notification_constructor", true)
    if not nc then return end
    nc:formatConstructor(Critmatic.db.profile.alertNotificationFormat.strings.critAlertNotificationFormat, true, true, "soundCrit")
end

function Critmatic:AlertGeneralFragment()
    local generalWidth = "300"
    return {
        maxMessages = {
            name = "Max Messages",
            desc = "Set the maximum number of messages",
            type = "range",
            min = 2,
            max = 8,
            step = 1,
            order = 1,
            width = generalWidth,
            get = function()
                return Critmatic.db.profile.alertNotificationFormat.global.maxMessages
            end,
            set = function(_, newVal)
                Critmatic.db.profile.alertNotificationFormat.global.maxMessages = newVal
            end,
        },
        resetMaxMessages = {
            name = "Reset Max Messages",
            type = "execute",
            order = 2,
            width = generalWidth,
            func = function()
                Critmatic.db.profile.alertNotificationFormat.global.maxMessages = Critmatic.db.defaults.profile.alertNotificationFormat.global.maxMessages
            end,
        },
        fadeTime = {
            name = "Fade Time",
            desc = "Set the fade time",
            type = "range",
            min = 0,
            max = 10,
            step = 0.1,
            order = 5,
            width = generalWidth,
            get = function()
                return Critmatic.db.profile.alertNotificationFormat.global.fadeTime
            end,
            set = function(_, newVal)
                Critmatic.db.profile.alertNotificationFormat.global.fadeTime = newVal
            end,
        },
        resetFadeTime = {
            name = "Reset Fade Time",
            type = "execute",
            order = 6,
            width = generalWidth,
            func = function()
                Critmatic.db.profile.alertNotificationFormat.global.fadeTime = Critmatic.db.defaults.profile.alertNotificationFormat.global.fadeTime
            end,
        },
        resetStartDelay = {
            name = "Reset Start Delay",
            type = "execute",
            order = 4,
            width = generalWidth,
            func = function()
                Critmatic.db.profile.alertNotificationFormat.global.startDelay = Critmatic.db.defaults.profile.alertNotificationFormat.global.startDelay
            end,
        },
        resetCountUpDuration = {
            name = "Reset Animation Length",
            type = "execute",
            order = 8,
            width = generalWidth,
            func = function()
                Critmatic.db.profile.alertNotificationFormat.global.countUpDuration = Critmatic.db.defaults.profile.alertNotificationFormat.global.countUpDuration
            end,
        },
        resetCountUpHold = {
            name = "Reset Stay After Animation",
            type = "execute",
            order = 10,
            width = generalWidth,
            func = function()
                Critmatic.db.profile.alertNotificationFormat.global.countUpHold = Critmatic.db.defaults.profile.alertNotificationFormat.global.countUpHold
            end,
        },
        resetPosition = {
            name = "Reset Position",
            type = "execute",
            order = 13,
            width = generalWidth,
            func = function()
                Critmatic.db.profile.alertNotificationFormat.position.xPos = Critmatic.db.defaults.profile.alertNotificationFormat.position.xPos
                Critmatic.db.profile.alertNotificationFormat.position.yPos = Critmatic.db.defaults.profile.alertNotificationFormat.position.yPos
            end,
        },
    }
end

function Critmatic:AlertMessageExtras()
    local lib = LibStub("LibMatic-Settings-1.0", true)
    if not (lib and lib.BuildAlertMessageControls) then return {} end
    local built = lib:BuildAlertMessageControls({
        names = {
            isUpper = L["options_alert_chat_notification_format_upper"],
            reset = L["options_alert_notification_format_reset"],
        },
        isUpper = {
            get = function()
                return Critmatic.db.profile.alertNotificationFormat.global.isUpper
            end,
            set = function(_, newVal)
                Critmatic.db.profile.alertNotificationFormat.global.isUpper = newVal
            end,
        },
        reset = ResetAlertSettingsToDefault,
    })
    local args = {}
    if built.isUpper then
        built.isUpper.desc = L["options_alert_notification_format_upper_desc"]
        built.isUpper.order = 2
        args.isUpper = built.isUpper
    end
    if built.reset then
        built.reset.desc = L["options_alert_notification_format_reset_desc"]
        built.reset.confirm = true
        built.reset.confirmText = L["options_alert_notification_format_reset_confirm"]
        built.reset.order = 100
        args.resetAlertSettings = built.reset
    end
    return args
end

function Critmatic:AlertFontFragment()
    local lib = LibStub("LibMatic-Settings-1.0", true)
    if not (lib and lib.BuildAlertFontControls) then return {} end
    local args = lib:BuildAlertFontControls({
        sizeMin = 8,
        sizeMax = 32,
        names = {
            font = L["options_alert_font"],
            fontSize = L["options_alert_font_size"],
            fontColor = L["options_alert_font_color_crit"],
            fontColorAlt = L["options_alert_font_c_non_crit"],
            shadowX = L["options_alert_font_shadow_x"],
            shadowY = L["options_alert_font_shadow_y"],
            shadowColor = L["options_alert_font_shadow_color"],
            shadowStrength = L["options_alert_font_shadow_strength"],
            reset = L["options_alert_font_reset"],
        },
        font = {
            get = function()
                return Critmatic.db.profile.fontSettings.font
            end,
            set = function(_, newVal)
                Critmatic.db.profile.fontSettings.font = newVal
            end,
        },
        fontSize = {
            get = function()
                return Critmatic.db.profile.fontSettings.fontSize
            end,
            set = function(_, newVal)
                Critmatic.db.profile.fontSettings.fontSize = newVal
            end,
        },
        fontColor = {
            get = function()
                local r, g, b = unpack(Critmatic.db.profile.fontSettings.fontColorCrit)
                return r, g, b
            end,
            set = function(_, r, g, b)
                Critmatic.db.profile.fontSettings.fontColorCrit = { r, g, b }
            end,
        },
        fontColorAlt = {
            get = function()
                local r, g, b = unpack(Critmatic.db.profile.fontSettings.fontColor)
                return r, g, b
            end,
            set = function(_, r, g, b)
                Critmatic.db.profile.fontSettings.fontColor = { r, g, b }
            end,
        },
        shadowX = {
            get = function()
                return Critmatic.db.profile.fontSettings.fontShadowSize[1]
            end,
            set = function(_, value)
                Critmatic.db.profile.fontSettings.fontShadowSize[1] = value
            end,
        },
        shadowY = {
            get = function()
                return Critmatic.db.profile.fontSettings.fontShadowSize[2]
            end,
            set = function(_, value)
                Critmatic.db.profile.fontSettings.fontShadowSize[2] = value
            end,
        },
        shadowColor = {
            get = function()
                return unpack(Critmatic.db.profile.fontSettings.fontShadowColor)
            end,
            set = function(_, r, g, b)
                Critmatic.db.profile.fontSettings.fontShadowColor = { r, g, b }
            end,
        },
        shadowStrength = {
            get = function() return Critmatic.db.profile.fontSettings.shadowStrength end,
            set = function(_, v) Critmatic.db.profile.fontSettings.shadowStrength = v end,
        },
        reset = ResetFontSettingsToDefault,
    })
    args.fontColor.desc = L["options_alert_font_color_crit_desc"]
    args.fontColor.width = "normal"
    args.fontColorAlt.desc = L["options_alert_font_c_non_crit_desc"]
    args.fontColorAlt.width = "normal"
    args.shadowX.desc = L["options_alert_font_shadow_x_desc"]
    args.shadowX.width = "normal"
    args.shadowY.desc = L["options_alert_font_shadow_y_desc"]
    args.shadowY.width = "normal"
    args.shadowColor.desc = L["options_alert_font_shadow_color_desc"]
    args.shadowStrength.desc = L["options_alert_font_shadow_strength_desc"]
    if args.reset then
        args.reset.desc = L["options_alert_font_reset_desc"]
        args.reset.confirm = true
        args.reset.confirmText = L["options_alert_font_reset_confirm"]
    end
    args.fontOutline = {
        name = L["options_alert_font_outline"],
        type = "select",
        values = {
            ["NONE"] = L["options_alert_font_none"],
            ["OUTLINE"] = L["options_alert_font_outline"],
            ["OUTLINEMONOCHROME"] = L["options_alert_font_outline_mono"],
            ["THICKOUTLINE"] = L["options_alert_font_outline_thick"],
            ["THICKOUTLINEMONOCHROME"] = L["options_alert_font_outline_thick_mono"],
        },
        width = "full",
        order = 5,
        get = function()
            return Critmatic.db.profile.fontSettings.fontOutline
        end,
        set = function(_, newVal)
            Critmatic.db.profile.fontSettings.fontOutline = newVal
        end,
    }
    args.fontColorCritHeal = {
        name = L["options_alert_font_color_crit_heal"],
        desc = L["options_alert_font_color_crit_heal_desc"],
        type = "color",
        order = 4.1,
        width = "normal",
        get = function() return unpack(Critmatic.db.profile.fontSettings.fontColorCritHeal) end,
        set = function(_, r, g, b) Critmatic.db.profile.fontSettings.fontColorCritHeal = { r, g, b } end,
    }
    args.fontColorHeal = {
        name = L["options_alert_font_color_heal"],
        desc = L["options_alert_font_color_heal_desc"],
        type = "color",
        order = 4.2,
        width = "normal",
        get = function() return unpack(Critmatic.db.profile.fontSettings.fontColorHeal) end,
        set = function(_, r, g, b) Critmatic.db.profile.fontSettings.fontColorHeal = { r, g, b } end,
    }
    local function alertColorsDisabled() return Critmatic.db.profile.fontSettings.useGlobalColors end
    args.fontColor.disabled = alertColorsDisabled
    args.fontColorAlt.disabled = alertColorsDisabled
    args.fontColorCritHeal.disabled = alertColorsDisabled
    args.fontColorHeal.disabled = alertColorsDisabled
    args.fontColorPetCrit = {
        name = L["appearance_color_pet_crit"],
        desc = L["appearance_color_pet_crit_desc"],
        type = "color",
        order = 4.3,
        width = "normal",
        disabled = alertColorsDisabled,
        get = function() return unpack(Critmatic.db.profile.fontSettings.fontColorPetCrit) end,
        set = function(_, r, g, b) Critmatic.db.profile.fontSettings.fontColorPetCrit = { r, g, b } end,
    }
    args.fontColorPetHit = {
        name = L["appearance_color_pet_value"],
        desc = L["appearance_color_pet_value_desc"],
        type = "color",
        order = 4.4,
        width = "normal",
        disabled = alertColorsDisabled,
        get = function() return unpack(Critmatic.db.profile.fontSettings.fontColorPetHit) end,
        set = function(_, r, g, b) Critmatic.db.profile.fontSettings.fontColorPetHit = { r, g, b } end,
    }
    return args
end
