---@class GrimmsUltrawide : AceAddon, AceEvent-3.0, AceHook-3.0, AceConsole-3.0
local GU = LibStub("AceAddon-3.0"):NewAddon("GrimmsUltrawide", "AceConsole-3.0", "AceHook-3.0", "AceEvent-3.0")
local AceConfig = LibStub("AceConfig-3.0")
local AceConfigDialog = LibStub("AceConfigDialog-3.0")
local AceConfigCmd = LibStub("AceConfigCmd-3.0")

_G["GrimmsUltrawide"] = GU

function GU:OnInitialize()
    local defaults = {
        global = {
            scaleEnabled = false,
            scaleFactor = 1.20,
            auctionator = false,
            disableSpellPush = false,
            minimapButton = {
                hide = false,
                minimapPos = 220,
            }
		}
    }

    local tocVersion = (select(4, GetBuildInfo()))
    local retail = tocVersion > 110000
    local classic = tocVersion < 50000
    local mop = tocVersion > 50000 and tocVersion < 110000

    if not classic then
        defaults.global.atrocityUI = {
            fonts = {
                resize = false,
                size = 16,
            },
            elvUI = {
                databars = false,
                disableBags = false,
                panels = false,
                minimapDataTexts = false,
                minimap = false,
                tooltip = false,
                unitFrames = false,
                guildRepairs = false,
                acceptInvitesFromGuildmates = false
            },
            sle = false,
            bigWigs = false,
            details = false,
            plater = {
                fonts = {
                    resize = false,
                    size = 8
                },
                friendly = false,
                globalScale = 1
            }
        }

        defaults.global.ellesmereUI = {
            fonts = {
                resize = false,
                size = 16,
            },
            layout = {
                panels = false,
                minimap = false,
                unitFrames = false,
                damageMeters = false,
                buffsObjectives = false,
            },
            bigWigs = false,
        }
    end

    self.db = LibStub("AceDB-3.0"):New("GrimmsUltrawideDB", defaults)

    local options = {
        name = "GrimmsUltrawide",
        handler = GU,
        type = "group",
        args = {
            general = {
                order = 1,
                name = "General Tweaks",
                type = "group",
                args = {
                    settings = {
                        order = 10,
                        type = "group",
                        name = "Scaling",
                        inline = true,
                        args = {
                            scaleEnabled = {
                                order = 10,
                                name = "Enable Scaling Fixes",
                                desc = "Attempts to scale frames to the desired factor directly, without modifying " ..
                                    "global scale settings.",
                                type = "toggle",
                                set = function(_, val) self.db.global.scaleEnabled = val end,
                                get = function() return self.db.global.scaleEnabled end
                            },
                            scaleFactor = {
                                order = 20,
                                name = "Scale Factor",
                                desc = "A percentage multiplier used to determine how much to scale.",
                                type = "range",
                                min = 1.00,
                                max = 2.00,
                                step = 0.01,
                                isPercent = true,
                                set = function(_, val) self.db.global.scaleFactor = val end,
                                get = function() return self.db.global.scaleFactor end
                            },
                            reminder = {
                                order = 30,
                                type = "description",
                                fontSize = "medium",
                                name = "You need to reload your UI after changing this.\n"
                            }
                        }
                    },
                    addons = {
                        order = 20,
                        type = "group",
                        name = "Other Stuff",
                        inline = true,
                        args = {
                            auctionator = {
                                name = "Auctionator Tweaks",
                                desc = "Hides WoW's default vendor pricing on the item tooltip. Only applies " ..
                                    "when Auctionator is installed.",
                                type = "toggle",
                                set = function(_, val)
                                    self.db.global.auctionator = val
                                    self:ApplyAuctionatorFix()
                                end,
                                get = function() return self.db.global.auctionator end
                            },
                            disableSpellPush = {
                                name = "Disable Spell Push",
                                desc = "Sets a CVar to stop spells from being automatically pushed onto your " ..
                                    "action bars. Note: Unchecking this does not restore the original value.",
                                type = "toggle",
                                set = function(_, val)
                                    self.db.global.disableSpellPush = val
                                    self:ApplySpellPushTweaks()
                                end,
                                get = function() return self.db.global.disableSpellPush end
                            },
                            showMinimapButton = {
                                name = "Show Minimap Button",
                                desc = "Show the GrimmsUltrawide button on the minimap.",
                                type = "toggle",
                                set = function(_, val)
                                    self.db.global.minimapButton.hide = not val
                                    self:UpdateMinimapButton()
                                end,
                                get = function() return not self.db.global.minimapButton.hide end
                            }
                        }
                    },
                    apply = {
                        order = 1000,
                        name = "Reload UI",
                        desc = "To apply scale factor changes, you need to reload your UI.",
                        type = "execute",
                        func = function() return ReloadUI() end
                    }
                }
            }
        }
    }

    if not classic then
        options.args.ellesmereUI = {
            order = 5,
            name = "AUI - EllesmereUI",
            type = "group",
            args = {
                heading = {
                    order = 1,
                    type = "group",
                    name = "How it Works",
                    inline = true,
                    args = {
                        description = {
                            type = "description",
                            fontSize = "medium",
                            name = "These settings are only applied when you click the `Apply Tweaks` button below. " ..
                                " You'll need to re-apply these settings every time you update or install EllesmereUI."
                        }
                    }
                },
                ultrawide = {
                    order = 10,
                    type = "group",
                    name = "Ultra-wide Tweaks",
                    inline = true,
                    args = {
                        unitFrames = {
                            name = "Unit Frame Positions",
                            desc = "Fixes unit frame positions, which are placed incorrectly on ultra-wide " ..
                                "resolutions.",
                            type = "toggle",
                            set = function(_, val) self.db.global.ellesmereUI.layout.unitFrames = val end,
                            get = function() return self.db.global.ellesmereUI.layout.unitFrames end
                        },
                        bigWigs = {
                            name = "BigWigs Bars",
                            desc = "Resizes BigWigs bars (268x22) and emphasized bars (270x25), and sets the " ..
                                "max bars shown to 5.",
                            type = "toggle",
                            set = function(_, val) self.db.global.ellesmereUI.bigWigs = val end,
                            get = function() return self.db.global.ellesmereUI.bigWigs end
                        },
                    },
                },
                fonts = {
                    order = 20,
                    type = "group",
                    name = "Font Tweaks",
                    inline = true,
                    args = {
                        resizeFonts = {
                            name = "Change Font Size",
                            desc = "Changes the general UI font size.",
                            type = "toggle",
                            set = function(_, val) self.db.global.ellesmereUI.fonts.resize = val end,
                            get = function() return self.db.global.ellesmereUI.fonts.resize end
                        },
                        size = {
                            name = "Desired Font Size",
                            desc = "Sets the font size to use when 'Change Font Size' is enabled.",
                            type = "range",
                            min = 8,
                            max = 30,
                            step = 1,
                            set = function(_, val) self.db.global.ellesmereUI.fonts.size = val end,
                            get = function() return self.db.global.ellesmereUI.fonts.size end
                        }
                    }
                },
                layout = {
                    order = 30,
                    type = "group",
                    name = "Panel Tweaks",
                    inline = true,
                    args = {
                        panels = {
                            name = "Bigger Chat Panels",
                            desc = "Increases the size of the chat panels.",
                            type = "toggle",
                            set = function(_, val) self.db.global.ellesmereUI.layout.panels = val end,
                            get = function() return self.db.global.ellesmereUI.layout.panels end
                        },
                        minimap = {
                            name = "Bigger Minimap",
                            desc = "Increases the size of the minimap.",
                            type = "toggle",
                            set = function(_, val) self.db.global.ellesmereUI.layout.minimap = val end,
                            get = function() return self.db.global.ellesmereUI.layout.minimap end
                        },
                        damageMeters = {
                            name = "Damage Meters",
                            desc = "Repositions and resizes the damage meter windows and their tooltip.",
                            type = "toggle",
                            set = function(_, val) self.db.global.ellesmereUI.layout.damageMeters = val end,
                            get = function() return self.db.global.ellesmereUI.layout.damageMeters end
                        },
                        buffsObjectives = {
                            name = "Buff/Debuff and Objective Frames",
                            desc = "Fixes the Buff/Debuff and Objective Tracker frame positions by importing " ..
                                "a Blizzard Edit Mode layout, separate from the SavedVariables tweaks above.",
                            type = "toggle",
                            set = function(_, val) self.db.global.ellesmereUI.layout.buffsObjectives = val end,
                            get = function() return self.db.global.ellesmereUI.layout.buffsObjectives end
                        },
                    }
                },
                apply = {
                    order = 1000,
                    name = "Apply Tweaks",
                    desc = "Applies any of the tweaks above that you have enabled.",
                    type = "execute",
                    func = function() return GU:ApplyEllesmereTweaks() end
                }
            }
        }

        options.args.atrocityUI = {
            order = 10,
            name = "AUI - ElvUI",
            type = "group",
            args = {
                heading = {
                    order = 1,
                    type = "group",
                    name = "How it Works",
                    inline = true,
                    args = {
                        description = {
                            type = "description",
                            fontSize = "medium",
                            name = "These settings are only applied when you click the `Apply Tweaks` button below. " ..
                                " You'll need to re-apply these settings every time you update or install AtrocityUI."
                        }
                    }
                },
                ultrawide = {
                    order = 10,
                    type = "group",
                    name = "Ultra-wide Tweaks",
                    inline = true,
                    args = {
                        unitFrames = {
                            name = "Unit Frame Positions",
                            desc = "Fixes unit frame positions, which are placed incorrectly on ultra-wide " ..
                                "resolutions.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.elvUI.unitFrames = val end,
                            get = function() return self.db.global.atrocityUI.elvUI.unitFrames end
                        },
                        bigWigs = {
                            name = "BigWigs Bars",
                            desc = "Resizes BigWigs bars to match the minimap width, and sets the max bars " ..
                                "shown to 5.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.bigWigs = val end,
                            get = function() return self.db.global.atrocityUI.bigWigs end
                        },
                        details = {
                            name = "Details Tweaks",
                            desc = "Fixes the Details! tooltip anchor for ultra-wide resolutions.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.details = val end,
                            get = function() return self.db.global.atrocityUI.details end
                        },
                    },
                },
                fonts = {
                    order = 20,
                    type = "group",
                    name = "Font Tweaks",
                    inline = true,
                    args = {
                        resizeFonts = {
                            name = "Change Font Size",
                            desc = "Changes the general UI font size.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.fonts.resize = val end,
                            get = function() return self.db.global.atrocityUI.fonts.resize end
                        },
                        size = {
                            name = "Desired Font Size",
                            desc = "Sets the font size to use when 'Change Font Size' is enabled.",
                            type = "range",
                            min = 8,
                            max = 30,
                            step = 1,
                            set = function(_, val) self.db.global.atrocityUI.fonts.size = val end,
                            get = function() return self.db.global.atrocityUI.fonts.size end
                        }
                    }
                },
                elvUI = {
                    order = 30,
                    type = "group",
                    name = "ElvUI Tweaks",
                    inline = true,
                    args = {
                        databars = {
                            name = "Data Bars",
                            desc = "Increases the size of the experience bar when shown.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.elvUI.databars = val end,
                            get = function() return self.db.global.atrocityUI.elvUI.databars end
                        },
                        disableBags = {
                            name = "Disable Bags",
                            desc = "Disables ElvUI's bags. Useful if you use a separate bag addon like " ..
                                "AdiBags instead.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.elvUI.disableBags = val end,
                            get = function() return self.db.global.atrocityUI.elvUI.disableBags end
                        },
                        panels = {
                            name = "Bigger Chat Panels",
                            desc = "Increases the size of the chat and damage meter panels.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.elvUI.panels = val end,
                            get = function() return self.db.global.atrocityUI.elvUI.panels end
                        },
                        minimapDataTexts = {
                            name = "Minimap Data Texts",
                            desc = "Enables the data texts displayed under the minimap.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.elvUI.minimapDataTexts = val end,
                            get = function() return self.db.global.atrocityUI.elvUI.minimapDataTexts end
                        },
                        minimap = {
                            name = "Bigger Minimap",
                            desc = "Increases the size of the minimap.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.elvUI.minimap = val end,
                            get = function() return self.db.global.atrocityUI.elvUI.minimap end
                        },
                        tooltip = {
                            name = "Tooltip Tweaks",
                            desc = "Disables the item count display and sets the tooltip modifier key to SHIFT.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.elvUI.tooltip = val end,
                            get = function() return self.db.global.atrocityUI.elvUI.tooltip end
                        },
                        guildRepairs = {
                            name = "Use Guild Repairs",
                            desc = "Automatically repairs your gear using guild funds.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.elvUI.guildRepairs = val end,
                            get = function() return self.db.global.atrocityUI.elvUI.guildRepairs end
                        },
                        autoAcceptInvites = {
                            name = "Auto Accept Invites",
                            desc = "Automatically accepts group invites from guild members and friends.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.elvUI.autoAcceptInvites = val end,
                            get = function() return self.db.global.atrocityUI.elvUI.autoAcceptInvites end
                        },
                    }
                },
                plater = {
                    order = 40,
                    type = "group",
                    name = "Plater Tweaks",
                    inline = true,
                    args = {
                        resizeFonts = {
                            order = 1,
                            name = "Change Font Size",
                            desc = "Changes the font size used on Plater nameplates.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.plater.fonts.resize = val end,
                            get = function() return self.db.global.atrocityUI.plater.fonts.resize end
                        },
                        size = {
                            order = 10,
                            name = "Desired Font Size",
                            desc = "Sets the font size to use when 'Change Font Size' is enabled.",
                            type = "range",
                            min = 6,
                            max = 30,
                            step = 1,
                            set = function(_, val) self.db.global.atrocityUI.plater.fonts.size = val end,
                            get = function() return self.db.global.atrocityUI.plater.fonts.size end
                        },
                        friendly = {
                            order = 20,
                            name = "Friendly Plates",
                            desc = "Automatically enables friendly nameplates in dungeons and raids.",
                            type = "toggle",
                            set = function(_, val) self.db.global.atrocityUI.plater.friendly = val end,
                            get = function() return self.db.global.atrocityUI.plater.friendly end
                        },
                        globalScale = {
                            order = 30,
                            name = "Global Scale",
                            desc = "Applies a custom scale to Plater frames.",
                            type = "range",
                            min = 1.00,
                            max = 2.00,
                            step = 0.01,
                            isPercent = true,
                            set = function(_, val) self.db.global.atrocityUI.plater.globalScale = val end,
                            get = function() return self.db.global.atrocityUI.plater.globalScale end
                        }
                    }
                },
                apply = {
                    order = 1000,
                    name = "Apply Tweaks",
                    desc = "Applies any of the tweaks above that you have enabled.",
                    type = "execute",
                    func = function() return GU:ApplyAtrocityTweaks() end
                }
            }
        }
    end

    AceConfig:RegisterOptionsTable("GrimmsUltrawide", options)
    local blizFrame, blizCategoryID = AceConfigDialog:AddToBlizOptions("GrimmsUltrawide", "GrimmsUltrawide")
    self.blizCategoryID = blizCategoryID

    self:RegisterChatCommand("gu", function(input)
        if not input or input:trim() == "" then
            Settings.OpenToCategory(blizCategoryID)
        elseif input:trim():lower() == "minimap" then
            GU:ToggleMinimapButton()
        else
            AceConfigCmd.HandleCommand(GU, "gu", "GrimmsUltrawide", input)
        end
    end)
end

function GU:Debug(...)
    local status, res = pcall(format, ...)
    if status then
        if DLAPI then DLAPI.DebugLog("GrimmsUltrawide", res) end
    end
end

function GU:SetupMinimapButton()
    local LDB = LibStub("LibDataBroker-1.1", true)
    local LibDBIcon = LibStub("LibDBIcon-1.0", true)

    if not LDB or not LibDBIcon then
        GU:Debug("LibDataBroker-1.1 or LibDBIcon-1.0 not found - minimap button disabled.")
        return
    end

    local dataobj = LDB:NewDataObject("GrimmsUltrawide", {
        type  = "launcher",
        label = "GrimmsUltrawide",
        icon  = "Interface\\AddOns\\GrimmsUltrawide\\Media\\icon",
        OnClick = function(_, button)
            if button == "LeftButton" then
                Settings.OpenToCategory(GU.blizCategoryID)
            elseif button == "RightButton" then
                GU.db.global.minimapButton.hide = true
                GU:UpdateMinimapButton()
                GU:Print("Minimap button hidden. Use |cffff9f00/gu minimap|r or the checkbox in settings to show it again.")
            end
        end,
        OnTooltipShow = function(tooltip)
            tooltip:AddLine("|cffff9f00GrimmsUltrawide|r")
            tooltip:AddLine(" ")
            tooltip:AddLine("|cffffffff Left-click|r to open settings")
            tooltip:AddLine("|cffffffff Right-click|r to hide this button")
            tooltip:AddLine("|cffffffff /gu minimap|r to toggle this button")
        end,
    })

    LibDBIcon:Register("GrimmsUltrawide", dataobj, self.db.global.minimapButton)
    self.minimapDataObj = dataobj
    self.libDBIcon = LibDBIcon
end

function GU:UpdateMinimapButton()
    if not self.libDBIcon then return end
    if self.db.global.minimapButton.hide then
        self.libDBIcon:Hide("GrimmsUltrawide")
    else
        self.libDBIcon:Show("GrimmsUltrawide")
    end

    self:RegisterEllesmereMinimapButton()
end

function GU:ToggleMinimapButton()
    self.db.global.minimapButton.hide = not self.db.global.minimapButton.hide
    self:UpdateMinimapButton()
    if self.db.global.minimapButton.hide then
        self:Print("Minimap button hidden. Use |cffff9f00/gu minimap|r or the checkbox in settings to show it again.")
    else
        self:Print("Minimap button shown.")
    end
end

function GU:Split(text, token)
    if token == nil then
        token = "%s"
    end
    local t = {}
    for str in string.gmatch(text, "([^" .. token .. "]+)") do
        table.insert(t, str)
    end
    return t
end

function GU:StartsWithIgnoreCase(val, starts)
    local lowerVal = string.lower(val)
    local lowerStarts = string.lower(starts)

    return string.sub(lowerVal, 1, #lowerStarts) == lowerStarts
end

function GU:ContainsIgnoreCase(val, search)
    local lowerVal = string.lower(val)
    local lowerSearch = string.lower(search)

    return string.find(lowerVal, lowerSearch, 1, true) ~= nil
end

function GU:OnEnable()
    self:ApplyAuctionatorFix()
    self:ApplySpellPushTweaks()
    self:ApplyScaling()
    self:SetupMinimapButton()
end

function GU:OnDisable()
    self:DisableAuctionatorFix()
    self:UnhookAll()
end
