---@type Orbit
local Orbit = Orbit
local L = Orbit.L
local OrbitEngine = Orbit.Engine

-- [ PLUGIN REGISTRATION ]----------------------------------------------------------------------------
local SYSTEM_ID = "Orbit_BagBar"
local DEFAULT_POSITION_X = -50
local DEFAULT_POSITION_Y = 40

local Plugin = Orbit:RegisterPlugin("Bag Bar", SYSTEM_ID, {
    displayName = L.PLG_NAME_BAG_BAR,
    defaults = {
        Scale = 100,
        Opacity = 100,
        Orientation = Enum.BagsOrientation.Horizontal,
        Direction = Enum.BagsDirection.Left,
    },
})

-- Apply NativeBarMixin for mouseOver helpers
Mixin(Plugin, Orbit.NativeBarMixin)

-- [ SETTINGS UI ]------------------------------------------------------------------------------------
function Plugin:AddSettings(dialog, systemFrame)
    local systemIndex = systemFrame.systemIndex or SYSTEM_ID
    local SB = OrbitEngine.SchemaBuilder

    local currentOrientation = self:GetSetting(systemIndex, "Orientation")

    -- Direction options depend on orientation
    local dirOpts
    if currentOrientation == Enum.BagsOrientation.Horizontal then
        dirOpts = {
            { text = L.PLU_BAG_DIR_LEFT, value = Enum.BagsDirection.Left },
            { text = L.PLU_BAG_DIR_RIGHT, value = Enum.BagsDirection.Right },
        }
    else
        dirOpts = {
            { text = L.PLU_BAG_DIR_UP, value = Enum.BagsDirection.Up },
            { text = L.PLU_BAG_DIR_DOWN, value = Enum.BagsDirection.Down },
        }
    end

    local schema = {
        hideNativeSettings = true,
        controls = {},
    }

    -- 1. Orientation
    SB:AddOrientationSettings(self, schema, systemIndex, dialog, systemFrame, {
        options = {
            { text = L.PLU_BAG_HORIZONTAL, value = Enum.BagsOrientation.Horizontal },
            { text = L.PLU_BAG_VERTICAL, value = Enum.BagsOrientation.Vertical },
        },
        default = Enum.BagsOrientation.Horizontal,
        onChange = function(val)
            self:SetSetting(systemIndex, "Orientation", val)

            if val == Enum.BagsOrientation.Horizontal then
                self:SetSetting(systemIndex, "Direction", Enum.BagsDirection.Left)
            else
                self:SetSetting(systemIndex, "Direction", Enum.BagsDirection.Up)
            end
            self:ApplySettings()

            OrbitEngine.Layout:Reset(dialog)
            self:AddSettings(dialog, systemFrame)
        end,
    })

    -- 2. Direction (Grow)
    table.insert(schema.controls, {
        type = "dropdown",
        key = "Direction",
        label = L.PLU_BAG_GROW,
        options = dirOpts,
        default = Enum.BagsDirection.Left,
    })

    -- 3. Scale
    SB:AddSizeSettings(self, schema, systemIndex, systemFrame, nil, nil, {
        key = "Scale",
        label = L.PLU_BAG_SCALE,
        default = 100,
        min = 50,
        max = 150,
    })

    OrbitEngine.Config:Render(dialog, systemFrame, self, schema)
end

-- [ LIFECYCLE ]--------------------------------------------------------------------------------------
function Plugin:OnLoad()
    -- Create Container
    self.frame = CreateFrame("Frame", "OrbitBagBarContainer", UIParent)
    self.frame:SetSize(200, 40) -- Initial size, will be resized to fit content
    self.frame:SetClampedToScreen(true) -- Prevent dragging off-screen
    self.frame.systemIndex = SYSTEM_ID
    self.frame.editModeName = self.displayName

    -- Anchor Options: Allow anchoring but disable property sync
    self.frame.anchorOptions = {
        horizontal = true,
        vertical = true,
    }

    -- Default Position
    self.frame:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", DEFAULT_POSITION_X, DEFAULT_POSITION_Y)

    -- Register to Orbit
    OrbitEngine.Frame:AttachSettingsListener(self.frame, self, SYSTEM_ID)
    OrbitEngine.Frame:RestorePosition(self.frame, self, SYSTEM_ID)

    self:RegisterStandardEvents()
    self:RegisterVisibilityEvents()
    self.mountedConfig = { frame = self.frame }
    if Orbit.OOCFadeMixin then Orbit.OOCFadeMixin:ApplyOOCFade(self.frame, self, SYSTEM_ID) end

    -- Event-driven initialization with retry
    self:TryCapture()
end

-- [ INITIALIZATION ]---------------------------------------------------------------------------------
function Plugin:TryCapture()
    if BagsBar then
        if InCombatLockdown() then
            Orbit.CombatManager:QueueUpdate(function()
                self:ReparentAll()
                self:ApplySettings()
            end)
        else
            self:ReparentAll()
            self:ApplySettings()
        end
        return true
    end

    if not self._captureRetryRegistered then
        self._captureRetryRegistered = true
        Orbit.EventBus:On("ORBIT_PLAYER_ENTERING_WORLD", function()
            if not self._captured then
                self:TryCapture()
            end
        end, self)
    end
    return false
end

-- [ LOGIC ]------------------------------------------------------------------------------------------
function Plugin:ReparentAll()
    if not BagsBar then
        return
    end
    if InCombatLockdown() then
        Orbit.CombatManager:QueueUpdate(function()
            self:ReparentAll()
        end)
        return
    end
    -- BagsBar parent shifts between UIParent and MicroMenuContainer per Blizzard's flow; both are sanctioned native parents.
    if not self:CaptureFromNativeParent(BagsBar, { UIParent, MicroMenuContainer }) then return end
    BagsBar:ClearAllPoints()
    BagsBar:SetPoint("CENTER", self.frame, "CENTER", 0, 0)
    BagsBar:Show()
    self._captured = true
    if BagsBar.Selection then
        BagsBar.Selection:SetAlpha(0)
        BagsBar.Selection:EnableMouse(false)
    end
    OrbitEngine.FrameGuard:Protect(BagsBar, self.frame)
    OrbitEngine.FrameGuard:UpdateProtection(BagsBar, self.frame, function()
        self:ApplySettings()
    end, { enforceShow = true })

    if not BagsBar._orbitLayoutHooked and BagsBar.Layout then
        hooksecurefunc(BagsBar, "Layout", function()
            C_Timer.After(0, function()
                self:SyncSize()
            end)
        end)
        BagsBar._orbitLayoutHooked = true
    end
end

-- Resize the container to BagsBar's content bounds. Guarded: the container parents the secure BagsBar, so SetSize is protected in combat.
function Plugin:SyncSize()
    local frame = self.frame
    if not frame or not BagsBar or not BagsBar:IsShown() then return end
    if InCombatLockdown() then
        Orbit.CombatManager:QueueUpdate(function()
            self:SyncSize()
        end)
        return
    end
    local w, h = BagsBar:GetSize()
    if w and h and w > 0 and h > 0 then
        local s = frame:GetEffectiveScale()
        frame:SetSize(OrbitEngine.Pixel:Snap(w, s), OrbitEngine.Pixel:Snap(h, s))
    end
end

-- [ SETTINGS APPLICATION ]---------------------------------------------------------------------------
function Plugin:ApplySettings()
    local frame = self.frame
    if not frame then
        return
    end
    if InCombatLockdown() then
        Orbit.CombatManager:QueueUpdate(function()
            self:ApplySettings()
        end)
        return
    end
    local scale, orientation, direction =
        self:GetSetting(SYSTEM_ID, "Scale") or 100, self:GetSetting(SYSTEM_ID, "Orientation"), self:GetSetting(SYSTEM_ID, "Direction")
    self:ReparentAll()
    frame:SetScale(scale / 100)
    frame:Show()

    if BagsBar then
        self:ApplyOrientation(BagsBar, orientation, Enum.BagsOrientation.Horizontal)
        BagsBar.direction = direction
        self:TriggerLayout(BagsBar)
        self:SyncSize()
    end

    self:ApplyMouseOver(frame, SYSTEM_ID)
end

-- [ BLIZZARD HIDER ]---------------------------------------------------------------------------------
Orbit:RegisterBlizzardHider("Bag Bar", function()
    if BagsBar then OrbitEngine.NativeFrame:SecureHide(BagsBar) end
end)
