---@type Tinkr, Bastion
Tinkr, Bastion = ...

---@type Diesal.GUI
local DiesalGUI = LibStub("DiesalGUI-2.0")
---@type Diesal.Tools
local DiesalTools = LibStub("DiesalTools-2.0")
---@type Diesal.Style
local DiesalStyle = LibStub("DiesalStyle-2.0")

-- ~~| Diesal Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local Colors = DiesalStyle.Colors
local HSL, ShadeColor, TintColor = DiesalTools.HSL, DiesalTools.ShadeColor, DiesalTools.TintColor
-- ~~| Lua Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local type, tonumber, select = type, tonumber, select
local pairs, ipairs, next = pairs, ipairs, next
local min, max = math.min, math.max
-- ~~| WoW Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local CreateFrame, UIParent, GetCursorPosition = CreateFrame, UIParent, GetCursorPosition
-- ~~| Button |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local Type = "DiesalToggle"
local Version = 1
-- ~~| Button Stylesheets |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local Stylesheet = {
    ["frame-background"] = {
        type = "texture",
        layer = "BACKGROUND",
        color = "000000",
        alpha = 0.60,
        position = -2,
    },
    ["frame-inline"] = {
        type = "outline",
        layer = "BORDER",
        color = "000000",
        alpha = 0.6,
        position = -2,
    },
    ["frame-outline"] = {
        type = "outline",
        layer = "BORDER",
        color = "FFFFFF",
        alpha = 0.1,
        position = -1,
    },
}
local checkBoxStyle = {
    base = {
        type = "texture",
        layer = "ARTWORK",
        color = Colors.UI_A400,
        position = -3,
    },
    disabled = {
        type = "texture",
        color = HSL(Colors.UI_Hue, Colors.UI_Saturation, 0.35),
    },
    enabled = {
        type = "texture",
        color = Colors.UI_A400,
    },
}

local wireFrame = {
    ["frame-white"] = {
        type = "outline",
        layer = "OVERLAY",
        color = "ffffff",
    },
}
-- ~~| Button Methods |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---@class Diesal.GUI.Toggle.Methods
local methods = {
    ---@param self DiesalToggle
    OnAcquire = function(self)
        self:ApplySettings()
        self:SetStylesheet(Stylesheet)
        self:Enable()
        -- self:SetStylesheet(wireFrameSheet)
        self.label:SetFontObject(DiesalFontNormal)
        self.label:SetText()
        self:Show()
    end,

    ---@param self DiesalToggle
    OnRelease = function(self) end,

    ---@param self DiesalToggle
    ApplySettings = function(self)
        local settings = self.settings
        local frame = self.frame

        self:SetWidth(settings.width)
        self:SetHeight(settings.height)
    end,

    ---@param self DiesalToggle
    ---@param value boolean
    SetChecked = function(self, value)
        self.settings.checked = value
        self.frame:SetChecked(value)

        self[self.settings.disabled and "Disable" or "Enable"](self)
    end,

    ---@param self DiesalToggle
    GetChecked = function(self)
        return self.settings.checked
    end,

    ---@param self DiesalToggle
    Disable = function(self)
        self.settings.disabled = true
        DiesalStyle:StyleTexture(self.check, self.checkBoxStyle and self.checkBoxStyle.disabled or checkBoxStyle.disabled)
        self.frame:Disable()
    end,

    ---@param self DiesalToggle
    Enable = function(self)
        self.settings.disabled = false
        DiesalStyle:StyleTexture(self.check, self.checkBoxStyle and self.checkBoxStyle.enabled or checkBoxStyle.enabled)
        self.frame:Enable()
    end,

    ---@param self DiesalToggle
    ---@param ... any
    RegisterForClicks = function(self, ...)
        self.frame:RegisterForClicks(...)
    end,

    ---@param self DiesalToggle
    ---@param text? string
    SetText = function(self, text)
        self.label:SetText(text)
        self.frame:SetHitRectInsets(0, -self.label:GetWidth(), 0, 0)
    end,
}

---@alias DiesalToggle Diesal.GUI.Object.Toggle

---@class Diesal.Style.CheckBox.Style
---@field base {type: "texture", layer: "ARTWORK", color: string, position: number}
---@field disabled {type: "texture", color: string}
---@field enabled {type: "texture", color: string}}

---@class Diesal.GUI.Toggle.Settings
---@field height number
---@field width number
---@field checked boolean
---@field disabled boolean
---@field tooltip? string

-- ~~| Button Constructor |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local function Constructor()
    ---@class Diesal.GUI.Object.Toggle : Diesal.GUI.ObjectBase, Diesal.GUI.Toggle.Methods
    ---@field check Texture
    ---@field settings Diesal.GUI.Toggle.Settings
    ---@field checkBoxStyle? Diesal.Style.CheckBox.Style
    ---@field label FontString
    local self = DiesalGUI:Create(Type, true)
    local frame = CreateFrame("CheckButton", nil, UIParent)
    local fontString = self:CreateRegion("FontString", "label", frame)
    self.frame = frame

    local c, a = 0.5, 0.5
    local tex = frame:CreateTexture(nil, "BACKGROUND")
    tex:SetAllPoints()
    tex:SetColorTexture(0, 0, 0, 0)

    -- ~~ Default Settings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    self.defaults = {
        height = 12,
        width = 12,
    }

    -- ~~ Events ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    -- OnAcquire, OnRelease, OnHeightSet, OnWidthSet
    -- OnValueChanged, OnEnter, OnLeave, OnDisable, OnEnable
    -- ~~ Construct ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    local check = self:CreateRegion("Texture", "check", frame)
    -- Setting self.check again is pointless when CreateRegion already does it....
    -- self.check = check

    DiesalStyle:StyleTexture(check, self.checkBoxStyle and self.checkBoxStyle.base or checkBoxStyle.base)
    frame:SetCheckedTexture(check)
    frame:SetScript("OnClick", function(this, button, ...)
        DiesalGUI:OnMouse(this, button)

        if not self.settings.disabled then
            self:SetChecked(not self.settings.checked)

            if self.settings.checked then
                PlaySound(856)
            else
                PlaySound(857)
            end

            self:FireEvent("OnValueChanged", self.settings.checked)
        end
    end)

    frame:SetScript("OnEnter", function(this)
        if self.settings.tooltip then
            GameTooltip:SetOwner(this, "ANCHOR_TOPLEFT", 0, 2)
            GameTooltip:AddLine(self.settings.tooltip)
            GameTooltip:Show()
        end
        self:FireEvent("OnEnter")
        tex:SetColorTexture(c, c, c, a)
        -- SetCursor([[Interface\Cursor\Cast]])
    end)

    frame:SetScript("OnLeave", function(this)
        if self.settings.tooltip then
            GameTooltip:Hide()
        end
        self:FireEvent("OnLeave")
        tex:SetColorTexture(0, 0, 0, 0)
        -- SetCursor(nil)
    end)

    frame:SetScript("OnDisable", function(this)
        self:FireEvent("OnDisable")
    end)
    frame:SetScript("OnEnable", function(this)
        self:FireEvent("OnEnable")
    end)
    ---@param this Frame
    frame:SetScript("OnShow", function(this)
        this:SetFrameStrata("FULLSCREEN")
    end)

    fontString:SetPoint("LEFT", frame, "RIGHT", 5, 0)
    fontString:SetHeight(15)
    fontString:SetWordWrap(false)

    -- ~~ Methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    self:SetMethods(methods)
    --[[ for method, func in pairs(methods) do
        self[method] = func
    end ]]
    -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    return self
end

DiesalGUI:RegisterObjectConstructor(Type, Constructor, Version)
