local pluginName, pluginShared = ...

local AppearanceMaticPink = "|cffffb6d9"

AppearanceMatic = LibStub("AceAddon-3.0"):NewAddon("AppearanceMatic", "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0")
pluginShared.Core = AppearanceMatic

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

local defaults = {
    profile = {
        generalSettings = {
            alertNotificationsEnabled = true,
            chatNotifications = true,
            isChangeLogAutoPopUpEnabled = true,
            loginBanner = true,
            updateNotify = true,
            debug = false,
            expansionInTooltip = true,
            hoverPreviewNaked = false,
            itemTooltipPreview = true,
            hideUnattainable = false,
        },
        fontSettings = {
            font = "Anton",
            fontOutline = "OUTLINEMONOCHROME",
            fontSize = 22,
            fontColor = { 1, 0.71, 0.85 },
            fontShadowSizeX = 3,
            fontShadowSizeY = -3,
            fontShadowColor = { 0.1, 0.1, 0.1 },
            shadowStrength = 0.85,
        },
        alertNotificationFormat = {
            isUpper = false,
            bounceStyle = "legacy",
            maxMessages = 4,
            startDelay = 0,
            fadeTime = 0.6,
            displayDuration = 5,
            cooldown = 0,
            xPos = 50,
            yPos = 72,
            useSharedPosition = true,
            shared = { x = 50, y = 72, rev = 0, maxAlerts = 5 },
            iconPop = true,
            iconPopScale = 1.5,
            stagger = 0.05,
            showIcon = true,
            iconSize = 24,
            bossSkull = true,
            skullStyle = "fanged",
            formats = {
                appearance = L["opt_default_format_appearance"],
                mount = L["opt_default_format_mount"],
            },
        },
        soundSettings = {
            slots = {
                appearance = "Level Up",
                mount = "Level Up",
            },
            muteAll = false,
            channel = "Master",
            rateLimit = 2,
            oncePerLogin = false,
            inCombat = true,
        },
        social = {
            guild = true,
            party = true,
            raid = true,
            battleground = true,
            emote = true,
        },
        changeLogPopUp = nil,
        lockoutsFrame = {
            shown = true,
            locked = false,
            scale = 1,
            alpha = 1,
        },
        lockoutsFont = {
            font = "Friz Quadrata TT",
            fontSize = 12,
            fontOutline = "",
        },
        guideArrow = {
            shown = true,
            locked = false,
            scale = 1,
            alpha = 1,
            hideTomTom = true,
            arrivalPing = true,
            preferOwnMount = false,
            useHearth = true,
            point = { point = "TOP", relPoint = "TOP", x = 30, y = -4 },
        },
        customMedia = {
            soundCache = {},
        },
        minimap = { hide = false },
    },
}

local ChangeLogLib = LibStub("LibMatic-ChangeLog-1.0", true)
if ChangeLogLib and ChangeLogLib.DefaultStyle then
    defaults.profile.changeLogPopUp = ChangeLogLib:DefaultStyle()
else
    defaults.profile.changeLogPopUp = {
        fontSettings = { font = "MoK", fontSize = 15, fontColor = { 0, 0, 0 }, fontOutline = "OUTLINEMONOCHROME" },
        borderAndBackgroundSettings = { backgroundTexture = "Blizzard Parchment 2", borderTexture = "Blizzard Achievement Wood", borderSize = 15 },
    }
end

local function _GetAddOnMetadata(addonName, field)
    if _G.GetAddOnMetadata then
        return _G.GetAddOnMetadata(addonName, field)
    end
    if _G.C_AddOns and _G.C_AddOns.GetAddOnMetadata then
        return _G.C_AddOns.GetAddOnMetadata(addonName, field)
    end
    return nil
end

local function _IsAddOnLoaded(addonName)
    if _G.IsAddOnLoaded then
        return _G.IsAddOnLoaded(addonName)
    end
    if _G.C_AddOns and _G.C_AddOns.IsAddOnLoaded then
        return _G.C_AddOns.IsAddOnLoaded(addonName)
    end
    return false
end

local SOUND_KIT_TO_NAME = {
    [888] = "Level Up",
}

local function MigrateLegacySettings(profile)
    local old = _G.AppearanceMaticDB and _G.AppearanceMaticDB.alerts
    if not old then
        return
    end
    if old.enabled ~= nil then
        profile.generalSettings.alertNotificationsEnabled = old.enabled and true or false
    end
    if old.sound ~= nil then
        local soundNumber = tonumber(old.sound)
        if soundNumber then
            local mapped = SOUND_KIT_TO_NAME[soundNumber]
            if mapped then
                profile.soundSettings.slots.appearance = mapped
                profile.soundSettings.slots.mount = mapped
            elseif soundNumber == 0 then
                profile.soundSettings.muteAll = true
            end
        end
    end
end

pluginShared.MigrateLegacySettings = MigrateLegacySettings

function AppearanceMatic:OnInitialize()
    self.db = LibStub("AceDB-3.0"):New("AppearanceMaticSettingsDB", defaults, true)
    pluginShared.db = self.db

    if not self.db.global._legacyAlertsMigrated then
        MigrateLegacySettings(self.db.profile)
        self.db.global._legacyAlertsMigrated = true
    end
    -- guild announcing is on by default again; the 0.5.0 build wrote guild=false into profiles, so
    -- that write is undone once and from here the box is the player's own
    if not self.db.global._socialGuildRejoined then
        if type(self.db.profile.social) == "table" then
            self.db.profile.social.guild = true
        end
        self.db.global._socialGuildRejoined = true
    end
    -- the Social boxes are on by default; a profile saved while a group box was off gets those on
    -- once (guild has its own shim above), from here the player's own choice stands
    if not self.db.global._socialAllOn then
        if type(self.db.profile.social) == "table" then
            for _, key in ipairs({ "party", "raid", "battleground", "emote" }) do
                self.db.profile.social[key] = true
            end
        end
        self.db.global._socialAllOn = true
    end

    local Broadcast = LibStub("LibMatic-Broadcast-1.0", true)
    if Broadcast then
        Broadcast:Register({
            name = "AppearanceMatic",
            commPrefix = "APPRMATICBC",
            electionEnabled = false,
        })
    end

    local SoundPack = LibStub("LibMatic-SoundPack-1.0", true)
    local LSM = LibStub("LibSharedMedia-3.0", true)
    if SoundPack and LSM then
        SoundPack:Register("AppearanceMatic", "Libs\\LibMatic\\")
    end

    local FontPack = LibStub("LibMatic-FontPack-1.0", true)
    if FontPack and LSM then
        FontPack:Register("AppearanceMatic", "Libs\\LibMatic\\")
    end

    local CustomMedia = LibStub("LibMatic-CustomMedia-1.0", true)
    if CustomMedia then
        CustomMedia:Register({
            addon = "AppearanceMatic",
            sounds = 10,
            fonts = 10,
            soundCache = self.db.profile.customMedia.soundCache,
        })
    end

    if pluginShared.Alert and pluginShared.Alert.RegisterSharedAlertStack then
        pluginShared.Alert:RegisterSharedAlertStack()
    end

    if pluginShared.BuildOptionsTable then
        local opts = pluginShared.BuildOptionsTable()
        local Settings = LibStub("LibMatic-Settings-1.0", true)
        if Settings then
            Settings:RegisterPanel({ appName = "AppearanceMaticOptions", displayName = "AppearanceMatic", options = opts })
        else
            LibStub("AceConfig-3.0"):RegisterOptionsTable("AppearanceMaticOptions", opts)
            LibStub("AceConfigDialog-3.0"):AddToBlizOptions("AppearanceMaticOptions", "AppearanceMatic")
        end
    end

    if pluginShared.Launcher then
        pluginShared.Launcher:Setup(self.db.profile)
    end
    self.db.RegisterCallback(self, "OnProfileChanged", "OnProfileSwitched")
    self.db.RegisterCallback(self, "OnProfileCopied", "OnProfileSwitched")
    self.db.RegisterCallback(self, "OnProfileReset", "OnProfileSwitched")

    local version = _GetAddOnMetadata("AppearanceMatic", "Version") or "0"
    self.version = version

    local function compareVersions(version1, version2)
        local function splitVersion(str)
            local parts = {}
            for part in string.gmatch(str, "[%d]+") do
                table.insert(parts, tonumber(part))
            end
            return parts
        end
        local parts1 = splitVersion(version1)
        local parts2 = splitVersion(version2)
        for i = 1, math.max(#parts1, #parts2) do
            local num1 = parts1[i] or 0
            local num2 = parts2[i] or 0
            if num1 > num2 then
                return true
            elseif num1 < num2 then
                return false
            end
        end
        return false
    end
    self.CompareVersions = compareVersions

    local oldVersion = self.db.global.lastSeenVersion
    if oldVersion and compareVersions(version, oldVersion) then
        if self.db.profile.generalSettings.isChangeLogAutoPopUpEnabled and pluginShared.ShowChangeLog then
            pluginShared.ShowChangeLog()
        end
    end
    self.db.global.lastSeenVersion = version

    local startup = LibStub("LibMatic-Startup-1.0", true)
    if startup then
        startup:Register({
            name = "AppearanceMatic",
            version = version,
            optionsCommand = "/am settings",
            helpCommand = "/am help",
            useFactionColors = false,
            brandColor = "ffb6d9",
            commands = {
                { command = "/am", desc = L["core_cmd_toggle_lockouts"] },
                { command = "/am settings", desc = L["core_cmd_settings"] },
                { command = "/am test [appearance|mount]", desc = L["core_cmd_test"] },
                { command = "/am stop", desc = L["core_cmd_stop"] },
                { command = "/am reset", desc = L["core_cmd_reset"] },
                { command = "/am here", desc = L["core_cmd_here"] },
                { command = "/am diag", desc = L["core_cmd_diag"] },
                { command = "/am profile", desc = L["core_cmd_profile"] },
                { command = "/am changelog", desc = L["core_cmd_changelog"] },
                { command = "/am help", desc = L["core_cmd_help"] },
            },
        })
    end
    self.startup = startup

    local versionCheck = LibStub("LibMatic-VersionCheck-1.0", true)
    if versionCheck then
        versionCheck:RegisterAddon("AppearanceMatic", version, {
            label = AppearanceMaticPink .. "AppearanceMatic|r",
            noticeText = L["update_available"],
        })
    end

    function AppearanceMatic:PrintBanner()
        if not self.db.profile.generalSettings.loginBanner then
            return
        end
        if startup then
            startup:PrintBanner("AppearanceMatic")
        end
    end

    if _IsAddOnLoaded("ElvUI") then
        self:ScheduleTimer("PrintBanner", 8)
    else
        self:ScheduleTimer("PrintBanner", 4)
    end
end

-- a profile switch re-reads the minimap button's state from the new profile
function AppearanceMatic:OnProfileSwitched()
    if pluginShared.Launcher and self.db then
        pluginShared.Launcher:Setup(self.db.profile)
    end
end

function AppearanceMatic:OpenSettings()
    local Settings = LibStub("LibMatic-Settings-1.0", true)
    if Settings then
        Settings:OpenPanel("AppearanceMaticOptions")
    elseif LibStub("AceConfigDialog-3.0", true) then
        LibStub("AceConfigDialog-3.0"):Open("AppearanceMaticOptions")
    end
end

pluginShared.OpenSettings = function()
    AppearanceMatic:OpenSettings()
end
