local pluginName, pluginShared = ...
local L = LibStub("AceLocale-3.0"):GetLocale("AppearanceMatic")

local function db()
    return pluginShared.db and pluginShared.db.profile
end

local function BuildGeneralPage(Settings)
    local args = Settings:BuildGeneralPage({
        name = L["opt_general_tab_name"],
        order = 1,
        currentAddon = "AppearanceMatic",
        bind = { table = function() return db().generalSettings end },
        toggles = {
            {
                key = "alertNotificationsEnabled",
                name = L["toggle_alerts_enabled"],
                desc = L["toggle_alerts_enabled_desc"],
                order = 1,
            },
        },
        support = {
            discordURL = "https://discord.gg/34JJyrnGGC",
            discordIcon = "Interface\\AddOns\\AppearanceMatic\\Media\\Textures\\discord.tga",
            coffeeURL = "https://buymeacoffee.com/infiniteloopalchemist",
            coffeeIcon = "Interface\\AddOns\\AppearanceMatic\\Media\\Textures\\bmc-logo.tga",
        },
        nav = {
            iconRoot = "Interface\\AddOns\\AppearanceMatic\\Media\\Textures\\",
            factionIcons = false,
            extraLinks = {
                { label = L["opt_x_link"], url = "https://x.com/infiniteloopalc", icon = "x-logo.tga" },
            },
        },
    })
    if not args then
        return nil
    end

    local extras = Settings:BuildGeneralExtrasControls({
        loginBanner = {
            get = function() return db().generalSettings.loginBanner end,
            set = function(_, v) db().generalSettings.loginBanner = v end,
        },
        updateNotify = {
            get = function() return db().generalSettings.updateNotify end,
            set = function(_, v) db().generalSettings.updateNotify = v end,
        },
        chatNotifications = {
            get = function() return db().generalSettings.chatNotifications end,
            set = function(_, v) db().generalSettings.chatNotifications = v end,
        },
        debug = {
            get = function() return db().generalSettings.debug end,
            set = function(_, v) db().generalSettings.debug = v end,
        },
    })
    if extras then
        -- the login line is the welcome message: it names the version and the help command
        if extras.loginBanner then
            extras.loginBanner.name = L["toggle_welcome_message"]
            extras.loginBanner.desc = L["toggle_welcome_message_desc"]
        end
        for k, v in pairs(extras) do
            args.args[k] = v
        end
    end

    local tooltip = Settings:BuildTooltipControls({
        enabled = {
            get = function() return db().generalSettings.expansionInTooltip end,
            set = function(_, v) db().generalSettings.expansionInTooltip = v end,
        },
        names = {
            tooltipEnabled = L["tooltip_control_name"],
            tooltipEnabledDesc = L["tooltip_control_desc"],
        },
    })
    if tooltip then
        tooltip.itemTooltipPreview = {
            type = "toggle",
            name = L["item_tooltip_preview_name"],
            desc = L["item_tooltip_preview_desc"],
            order = 45,
            width = "full",
            get = function() return db().generalSettings.itemTooltipPreview ~= false end,
            set = function(_, v)
                db().generalSettings.itemTooltipPreview = v and true or false
                local lockouts = pluginShared.Lockouts
                if not v and lockouts and lockouts.HideHoverPreview then
                    lockouts:HideHoverPreview()
                end
            end,
        }
        tooltip.hoverPreviewNaked = {
            type = "toggle",
            name = L["hover_preview_naked_name"],
            desc = L["hover_preview_naked_desc"],
            order = 50,
            width = "full",
            get = function() return db().generalSettings.hoverPreviewNaked == true end,
            set = function(_, v) db().generalSettings.hoverPreviewNaked = v and true or false end,
        }
        tooltip.hideUnattainable = {
            type = "toggle",
            name = L["toggle_hide_unattainable"],
            desc = L["toggle_hide_unattainable_desc"],
            order = 60,
            width = "full",
            get = function() return db().generalSettings.hideUnattainable == true end,
            set = function(_, v)
                db().generalSettings.hideUnattainable = v and true or false
                local lockouts = pluginShared.Lockouts
                if lockouts and lockouts.ScheduleRebuild and lockouts.panel and lockouts.panel:IsShown() then
                    lockouts:ScheduleRebuild()
                end
            end,
        }
        tooltip.minimapButton = {
            type = "toggle",
            name = L["toggle_minimap_button"],
            desc = L["toggle_minimap_button_desc"],
            order = 70,
            width = "full",
            get = function() return pluginShared.Launcher and pluginShared.Launcher:MinimapShown(db()) or false end,
            set = function(_, v)
                if pluginShared.Launcher then
                    pluginShared.Launcher:SetMinimapShown(db(), v and true or false)
                end
            end,
        }
        args.args.tooltipGroup = {
            type = "group",
            name = L["tooltip_control_name"],
            order = 20,
            inline = true,
            args = tooltip,
        }
    end


    return args
end

-- The Widget Panel tab (after Alerts): what the panel is, then the window controls and its font
local function BuildPanelPage(Settings)
    local Lockouts = pluginShared.Lockouts
    if not Lockouts then
        return nil
    end
    local page = {
        intro = {
            type = "description",
            order = 0,
            width = "full",
            fontSize = "medium",
            name = L["opt_panel_tab_desc"],
        },
    }
    local frame = Settings:BuildFrameControls({
        frameName = L["lockouts_frame_name"],
        show = {
            get = function() return AppearanceMaticDB and AppearanceMaticDB.widget and AppearanceMaticDB.widget.shown ~= false end,
            set = function(_, v)
                if v then
                    Lockouts:EnsurePanel():Show()
                else
                    Lockouts:EnsurePanel():Hide()
                end
            end,
        },
        locked = {
            get = function() return Lockouts:IsLocked() end,
            set = function(_, v) Lockouts:SetLocked(v) end,
        },
        scale = {
            get = function() return Lockouts:GetScale() end,
            set = function(_, v) Lockouts:SetScale(v) end,
        },
        alpha = {
            get = function() return Lockouts:GetAlpha() end,
            set = function(_, v) Lockouts:SetAlpha(v) end,
        },
        resetPosition = function() Lockouts:ResetPosition() end,
    })
    if frame then
        page.lockoutsFrameGroup = {
            type = "group",
            name = L["lockouts_frame_name"],
            order = 10,
            inline = true,
            args = frame,
        }
    end
    -- one face, size and outline for everything in the panel (the face only on English clients;
    -- other languages draw with the game's own font for their script)
    if Lockouts.FontSettings and Lockouts.RefreshFonts then
        local function fontDB() return Lockouts:FontSettings() end
        local fontControls = Settings:BuildAlertFontControls({
            sizeMin = 8,
            sizeMax = 30,
            font = {
                get = function() return fontDB().font end,
                set = function(_, v) fontDB().font = v Lockouts:RefreshFonts() end,
            },
            fontSize = {
                get = function() return fontDB().fontSize end,
                set = function(_, v) fontDB().fontSize = v Lockouts:RefreshFonts() end,
            },
            fontOutline = {
                get = function() return fontDB().fontOutline end,
                set = function(_, v) fontDB().fontOutline = v Lockouts:RefreshFonts() end,
            },
            reset = function() Lockouts:ResetFontSettings() end,
            names = {
                font = L["lockfont_face"],
                fontSize = L["lockfont_size"],
                fontOutline = L["lockfont_outline"],
                reset = L["lockfont_reset"],
            },
        })
        if fontControls then
            if fontControls.font then
                fontControls.font.disabled = function() return not Lockouts:CustomFontsAllowed() end
            end
            fontControls.localeNote = {
                type = "description",
                order = 0,
                fontSize = "medium",
                name = L["lockfont_locale_note"],
                hidden = function() return Lockouts:CustomFontsAllowed() end,
            }
            page.lockoutsFontGroup = {
                type = "group",
                name = L["lockfont_group_name"],
                order = 20,
                inline = true,
                args = fontControls,
            }
        end
    end
    return {
        type = "group",
        name = L["opt_panel_tab_name"],
        desc = L["opt_panel_tab_desc"],
        order = 2.5,
        args = page,
    }
end

-- The Guide Arrow tab (after Sound): what the arrow is, then its window controls and behaviour
local function BuildArrowPage(Settings)
    local GuideArrow = pluginShared.GuideArrow
    if not GuideArrow then
        return nil
    end
    local ga = function() return db().guideArrow end
    local arrowControls = Settings:BuildFrameControls({
        frameName = L["guide_arrow_name"],
        show = {
            get = function() return ga().shown ~= false end,
            set = function(_, v) ga().shown = v and true or false GuideArrow:RefreshChrome() end,
        },
        locked = {
            get = function() return ga().locked end,
            set = function(_, v) ga().locked = v end,
        },
        scale = {
            get = function() return ga().scale or 1 end,
            set = function(_, v) ga().scale = v GuideArrow:RefreshChrome() end,
        },
        alpha = {
            get = function() return ga().alpha or 1 end,
            set = function(_, v) ga().alpha = v GuideArrow:RefreshChrome() end,
        },
        resetPosition = function() GuideArrow:ResetPosition() end,
    }) or {}
    arrowControls.hideTomTom = {
        type = "toggle", width = "full", order = 40,
        name = L["toggle_hide_tomtom"], desc = L["toggle_hide_tomtom_desc"],
        get = function() return ga().hideTomTom end,
        set = function(_, v) ga().hideTomTom = v and true or false if not v then GuideArrow:RestoreTomTom() end end,
    }
    arrowControls.preferOwnMount = {
        type = "toggle", width = "full", order = 42,
        name = L["toggle_prefer_own_mount"], desc = L["toggle_prefer_own_mount_desc"],
        get = function() return ga().preferOwnMount end,
        set = function(_, v) ga().preferOwnMount = v and true or false end,
    }
    arrowControls.useHearth = {
        type = "toggle", width = "full", order = 43,
        name = L["toggle_hearth_hops"], desc = L["toggle_hearth_hops_desc"],
        get = function() return ga().useHearth ~= false end,
        set = function(_, v) ga().useHearth = v and true or false end,
    }
    arrowControls.arrivalPing = {
        type = "toggle", width = "full", order = 41,
        name = L["toggle_arrival_ping"], desc = L["toggle_arrival_ping_desc"],
        get = function() return ga().arrivalPing end,
        set = function(_, v) ga().arrivalPing = v and true or false end,
    }
    arrowControls.intro = {
        type = "description",
        order = 0,
        width = "full",
        fontSize = "medium",
        name = L["opt_arrow_tab_desc"],
    }
    return {
        type = "group",
        name = L["guide_arrow_name"],
        desc = L["opt_arrow_tab_desc"],
        order = 3.5,
        args = arrowControls,
    }
end

-- The Detection tab (after Alerts): sibling addons on this client, each with its card (icon,
-- name, the switch that sits off until it is installed, description, status, link)
local function BuildDetectionPage(Settings)
    local Detection = pluginShared.Detection
    if not Detection then
        return nil
    end
    local entry
    for _, e in ipairs((Settings.GetRoster and Settings:GetRoster()) or {}) do
        if e.key == "GearMatic" then
            entry = e
        end
    end
    local iconRoot = "Interface\\AddOns\\AppearanceMatic\\Media\\Textures\\"
    local page = {
        gearmaticName = {
            type = "description", order = 10, width = "full", fontSize = "medium",
            name = "|cffffffff" .. ((entry and entry.displayName) or "GearMatic") .. "|r",
            image = iconRoot .. ((entry and entry.allianceIcon) or "gearmatic-icon.tga"),
            imageWidth = 24, imageHeight = 24,
        },
        gearmaticSwitch = {
            type = "description", order = 11, width = "full", fontSize = "medium",
            name = function() return Detection:StatusText("GearMatic") end,
            image = function() return Detection:SwitchTexture("GearMatic") end,
            imageWidth = 40, imageHeight = 20,
        },
        gearmaticIntro = {
            type = "description", order = 12, width = "full", fontSize = "medium",
            name = L["detect_gearmatic_intro"],
        },
        gearmaticAutoSell = {
            type = "description", order = 13, width = "full", fontSize = "medium",
            name = function() return "|cffffffff" .. Detection:AutoSellText() .. "|r" end,
            hidden = function() return not Detection:Installed("GearMatic") end,
        },
        gearmaticAutoRepair = {
            type = "description", order = 14, width = "full", fontSize = "medium",
            name = function() return "|cffffffff" .. Detection:AutoRepairText() .. "|r" end,
            hidden = function() return not Detection:Installed("GearMatic") end,
        },
        gearmaticKeep = {
            type = "description", order = 15, width = "full", fontSize = "medium",
            name = "|cff40ff40" .. L["detect_keep_note"] .. "|r",
            hidden = function() return Detection:GearMaticState() ~= "installed" end,
        },
        gearmaticDesc = {
            type = "description", order = 10.5, width = "full", fontSize = "small",
            name = function() return (Settings.GetAddonDescription and Settings:GetAddonDescription("GearMatic")) or "" end,
        },
        gearmaticLink = {
            type = "input", order = 17, width = "full", name = "",
            get = function() return (entry and entry.url) or "https://www.curseforge.com/wow/addons/gearmatic" end,
            set = function() end,
        },
    }
    return {
        type = "group",
        name = L["opt_detection_tab_name"],
        desc = L["opt_detection_tab_desc"],
        order = 2.2,
        args = page,
    }
end

local function BuildAlertPage(Settings)
    local fmt = function() return db().alertNotificationFormat end

    local globals = Settings:BuildAlertGlobalsControls({
        delay = {
            get = function() return fmt().startDelay end,
            set = function(_, v) fmt().startDelay = v end,
        },
        maxMessages = {
            get = function() return fmt().maxMessages end,
            set = function(_, v) fmt().maxMessages = v end,
        },
        displayDuration = {
            get = function() return fmt().displayDuration end,
            set = function(_, v) fmt().displayDuration = v end,
        },
        fadeTime = {
            get = function() return fmt().fadeTime end,
            set = function(_, v) fmt().fadeTime = v end,
        },
        cooldown = {
            get = function() return fmt().cooldown end,
            set = function(_, v) fmt().cooldown = v end,
        },
        resetPosition = function()
            fmt().xPos = 50
            fmt().yPos = 72
        end,
    }) or {}

    local animation = Settings:BuildAnimationControls({
        iconPop = {
            get = function() return fmt().iconPop end,
            set = function(_, v) fmt().iconPop = v end,
        },
        iconPopScale = {
            get = function() return fmt().iconPopScale end,
            set = function(_, v) fmt().iconPopScale = v end,
        },
        stagger = {
            get = function() return fmt().stagger end,
            set = function(_, v) fmt().stagger = v end,
        },
    }) or {}
    for k, v in pairs(animation) do
        globals[k] = v
    end

    local icon = Settings:BuildAlertIconControls({
        enabled = {
            get = function() return fmt().showIcon end,
            set = function(_, v) fmt().showIcon = v end,
        },
        size = {
            get = function() return fmt().iconSize end,
            set = function(_, v) fmt().iconSize = v end,
        },
    }) or {}
    for k, v in pairs(icon) do
        globals[k] = v
    end

    globals.bossSkull = {
        type = "toggle", width = "full", order = 43,
        name = L["toggle_boss_skull"],
        desc = L["toggle_boss_skull_desc"],
        get = function() return fmt().bossSkull end,
        set = function(_, v) fmt().bossSkull = v end,
    }
    local markers = Settings:BuildMarkerControls({
        addon = "AppearanceMatic",
        order = 44,
        skullStyle = {
            get = function() return fmt().skullStyle end,
            set = function(_, v) fmt().skullStyle = v end,
            disabled = function() return not fmt().bossSkull end,
        },
    }) or {}
    for k, v in pairs(markers) do
        globals[k] = v
    end

    local font = Settings:BuildAlertFontControls({
        font = {
            get = function() return db().fontSettings.font end,
            set = function(_, v) db().fontSettings.font = v end,
        },
        fontSize = {
            get = function() return db().fontSettings.fontSize end,
            set = function(_, v) db().fontSettings.fontSize = v end,
        },
        fontColor = {
            get = function()
                local c = db().fontSettings.fontColor
                return c[1], c[2], c[3]
            end,
            set = function(_, r, g, b)
                local c = db().fontSettings.fontColor
                c[1], c[2], c[3] = r, g, b
            end,
        },
        fontOutline = {
            get = function() return db().fontSettings.fontOutline end,
            set = function(_, v) db().fontSettings.fontOutline = v end,
        },
        shadowX = {
            get = function() return db().fontSettings.fontShadowSizeX end,
            set = function(_, v) db().fontSettings.fontShadowSizeX = v end,
        },
        shadowY = {
            get = function() return db().fontSettings.fontShadowSizeY end,
            set = function(_, v) db().fontSettings.fontShadowSizeY = v end,
        },
        shadowColor = {
            get = function()
                local c = db().fontSettings.fontShadowColor
                return c[1], c[2], c[3]
            end,
            set = function(_, r, g, b)
                local c = db().fontSettings.fontShadowColor
                c[1], c[2], c[3] = r, g, b
            end,
        },
        shadowStrength = {
            get = function() return db().fontSettings.shadowStrength end,
            set = function(_, v) db().fontSettings.shadowStrength = v end,
        },
        reset = function()
            local f = db().fontSettings
            f.font, f.fontOutline, f.fontSize = "Anton", "OUTLINEMONOCHROME", 22
            f.fontColor = { 1, 0.71, 0.85 }
            f.fontShadowSizeX, f.fontShadowSizeY = 3, -3
            f.fontShadowColor = { 0.1, 0.1, 0.1 }
            f.shadowStrength = 0.85
        end,
    })

    local messageExtras = Settings:BuildAlertMessageControls({
        isUpper = {
            get = function() return fmt().isUpper end,
            set = function(_, v) fmt().isUpper = v end,
        },
    })

    return Settings:BuildAlertPage({
        name = L["opt_alerts_tab_name"],
        order = 2,
        appName = "AppearanceMaticOptions",
        bind = { table = function() return fmt().formats end },
        notificationTypes = {
            {
                key = "appearance",
                title = L["notif_appearance_title"],
                desc = L["notif_appearance_desc"],
                defaultFormat = L["opt_default_format_appearance"],
                preview = function() pluginShared.Alert:Preview("appearance") end,
            },
            {
                key = "mount",
                title = L["notif_mount_title"],
                desc = L["notif_mount_desc"],
                defaultFormat = L["opt_default_format_mount"],
                preview = function() pluginShared.Alert:Preview("mount") end,
            },
        },
        globals = globals,
        font = font,
        messageExtras = messageExtras,
        bounce = {
            get = function() return fmt().bounceStyle end,
            set = function(_, v) fmt().bounceStyle = v end,
        },
        position = {
            get = function() return fmt().xPos, fmt().yPos end,
            set = function(x, y) fmt().xPos, fmt().yPos = x, y end,
            default = function() return 50, 72 end,
            close = function() pluginShared.OpenSettings() end,
            reopen = function() pluginShared.OpenSettings() end,
        },
        sharedPosition = {
            get = function() return fmt().useSharedPosition ~= false end,
            set = function(_, v) fmt().useSharedPosition = v end,
        },
    })
end

local function BuildSoundPage(Settings)
    local sound = function() return db().soundSettings end
    local args = Settings:BuildSoundPage({
        name = L["opt_sound_tab_name"],
        order = 3,
        bind = { table = function() return sound().slots end },
        slots = {
            { key = "appearance", label = L["sound_slot_appearance"] },
            { key = "mount", label = L["sound_slot_mount"] },
        },
        muteToggle = {
            key = "muteAll",
            get = function() return sound().muteAll end,
            set = function(_, v) sound().muteAll = v end,
        },
        scan = {
            addon = "AppearanceMatic",
        },
    })
    if not args then
        return nil
    end

    local extras = Settings:BuildSoundExtrasControls({
        channel = {
            get = function() return sound().channel end,
            set = function(_, v) sound().channel = v end,
        },
        rateLimit = {
            get = function() return sound().rateLimit end,
            set = function(_, v) sound().rateLimit = v end,
        },
        oncePerLogin = {
            get = function() return sound().oncePerLogin end,
            set = function(_, v) sound().oncePerLogin = v end,
        },
        inCombat = {
            get = function() return sound().inCombat end,
            set = function(_, v) sound().inCombat = v end,
        },
    })
    if extras then
        for k, v in pairs(extras) do
            args.args[k] = v
        end
    end
    return args
end

local function BuildSocialPage(Settings)
    return Settings:BuildSocialPage({
        name = L["opt_social_tab_name"],
        order = 4,
        bind = { table = function() return db().social end },
        channels = {
            { key = "party" },
            { key = "raid" },
            { key = "guild" },
            { key = "battleground" },
            { key = "emote", name = L["opt_emote_channel_name"] },
        },
    })
end

-- The FAQ tab (before Change Log): the questions new collectors actually ask, answered in place.
-- Each row is one locale pair; the question draws in the addon's pink, the answer under it.
local FAQ_ENTRIES = {
    { "faq_best_q", "faq_best_a" },
    { "faq_start_q", "faq_start_a" },
    { "faq_guides_q", "faq_guides_a" },
    { "faq_travel_q", "faq_travel_a" },
    { "faq_beta_q", "faq_beta_a" },
    { "faq_wording_q", "faq_wording_a" },
    { "faq_translate_q", "faq_translate_a" },
    { "faq_tomtom_q", "faq_tomtom_a" },
}

local function BuildFAQPage()
    local page = {
        intro = {
            type = "description", order = 0, width = "full", fontSize = "medium",
            name = L["opt_faq_tab_desc"] .. "\n",
        },
    }
    for position, entry in ipairs(FAQ_ENTRIES) do
        page["entry" .. position] = {
            type = "description", order = position, width = "full", fontSize = "medium",
            name = "|cffffb6d9" .. L[entry[1]] .. "|r\n" .. L[entry[2]] .. "\n",
        }
    end
    return {
        type = "group",
        name = L["opt_faq_tab_name"],
        order = 79,
        args = page,
    }
end

local function BuildChangeLogPage(Settings)
    return Settings:BuildChangeLogPage({
        name = L["opt_changelog_tab_name"],
        order = 80,
        profile = function() return db().changeLogPopUp end,
        showPopupToggle = {
            get = function() return db().generalSettings.isChangeLogAutoPopUpEnabled end,
            set = function(_, v) db().generalSettings.isChangeLogAutoPopUpEnabled = v end,
        },
        openNow = {
            func = function()
                if pluginShared.ShowChangeLog then
                    pluginShared.ShowChangeLog()
                end
            end,
        },
    })
end

function pluginShared.BuildOptionsTable()
    local Settings = LibStub("LibMatic-Settings-1.0", true)
    local args = {}
    if Settings then
        args.general_tab = BuildGeneralPage(Settings)
        args.alert_tab = BuildAlertPage(Settings)
        args.detection_tab = BuildDetectionPage(Settings)
        args.panel_tab = BuildPanelPage(Settings)
        args.arrow_tab = BuildArrowPage(Settings)
        args.sound_tab = BuildSoundPage(Settings)
        args.social_tab = BuildSocialPage(Settings)
        args.faq_tab = BuildFAQPage()
        args.changeLog_tab = BuildChangeLogPage(Settings)
        args.ignore_tab = pluginShared.Lockouts:IgnoreCharacters():BuildSettingsTab(85)
        args.profiles_tab = Settings:BuildProfilesPage({
            db = pluginShared.db,
            name = L["opt_profiles_tab_name"],
            order = 90,
        })
    end
    return { name = L["opt_options_title"], type = "group", args = args }
end
