--[[
    Commander 3.0 - Drag Feedback System

    Visual feedback during tab/window dragging:
    - Ghost label following cursor showing current action
    - Insert indicator (vertical line between tabs)
    - Drop highlight overlay on target window
]]

local ADDON_NAME, C3 = ...

-------------------------------------------------------------------------------
-- Drag Feedback Module
-------------------------------------------------------------------------------

local DragFeedback = {
    ghostFrame = nil,
    insertIndicator = nil,
    dropHighlight = nil,
    active = false,
}

C3.DragFeedback = DragFeedback

-- Colors for different actions (Nord palette)
local COLORS = {
    neutral = { 0.30, 0.34, 0.42, 0.9 },    -- nord3 - dragging
    detach = { 0.64, 0.75, 0.55, 0.9 },     -- nord14 - new window
    move = { 0.64, 0.75, 0.55, 0.9 },       -- nord14 - move to window
    merge = { 0.64, 0.75, 0.55, 0.9 },      -- nord14 - merge windows
    insert = { 0.82, 0.53, 0.44, 0.9 },     -- nord12 - insert between
    swap = { 0.71, 0.56, 0.68, 0.9 },       -- nord15 - swap tabs
    invalid = { 0.75, 0.38, 0.42, 0.9 },    -- nord11 - cannot drop
}

local function getHighlightAnchor(targetWindow)
    if not targetWindow then return nil, false end

    local tabs = targetWindow.tabs
    local tabCount = tabs and tabs.GetTabCount and tabs:GetTabCount() or 0
    if targetWindow.tabBar and targetWindow.tabBar:IsShown() and tabCount > 1 then
        return targetWindow.tabBar, true
    end

    if targetWindow.frame then
        return targetWindow.frame, false
    end

    return nil, false
end

local function applyHighlightColor(highlight, color, isTabBar)
    if not highlight or not color then return end

    local r, g, b = color[1], color[2], color[3]
    local baseAlpha = color[4] or 0.9
    local fillAlpha = isTabBar and 0.18 or 0.12
    local borderAlpha = isTabBar and math.min(baseAlpha, 0.9) or math.min(baseAlpha, 0.7)

    highlight.fill:SetColorTexture(r, g, b, fillAlpha)
    highlight.top:SetColorTexture(r, g, b, borderAlpha)
    highlight.bottom:SetColorTexture(r, g, b, borderAlpha)
    highlight.left:SetColorTexture(r, g, b, borderAlpha)
    highlight.right:SetColorTexture(r, g, b, borderAlpha)
end

-------------------------------------------------------------------------------
-- Ghost Label Frame
-------------------------------------------------------------------------------

local function CreateGhostFrame()
    if DragFeedback.ghostFrame then
        return DragFeedback.ghostFrame
    end

    local ghost = CreateFrame("Frame", "Commander3DragGhost", UIParent)
    ghost:SetFrameStrata("TOOLTIP")
    ghost:SetFrameLevel(1000)
    ghost:SetSize(100, 22)

    -- Background
    ghost.bg = ghost:CreateTexture(nil, "BACKGROUND")
    ghost.bg:SetAllPoints()
    ghost.bg:SetColorTexture(unpack(COLORS.neutral))

    -- Border (nord9)
    ghost.border = {}
    local borderColor = { 0.51, 0.63, 0.76, 1 }

    ghost.border.top = ghost:CreateTexture(nil, "BORDER")
    ghost.border.top:SetColorTexture(unpack(borderColor))
    ghost.border.top:SetPoint("TOPLEFT", 0, 0)
    ghost.border.top:SetPoint("TOPRIGHT", 0, 0)
    ghost.border.top:SetHeight(1)

    ghost.border.bottom = ghost:CreateTexture(nil, "BORDER")
    ghost.border.bottom:SetColorTexture(unpack(borderColor))
    ghost.border.bottom:SetPoint("BOTTOMLEFT", 0, 0)
    ghost.border.bottom:SetPoint("BOTTOMRIGHT", 0, 0)
    ghost.border.bottom:SetHeight(1)

    ghost.border.left = ghost:CreateTexture(nil, "BORDER")
    ghost.border.left:SetColorTexture(unpack(borderColor))
    ghost.border.left:SetPoint("TOPLEFT", 0, 0)
    ghost.border.left:SetPoint("BOTTOMLEFT", 0, 0)
    ghost.border.left:SetWidth(1)

    ghost.border.right = ghost:CreateTexture(nil, "BORDER")
    ghost.border.right:SetColorTexture(unpack(borderColor))
    ghost.border.right:SetPoint("TOPRIGHT", 0, 0)
    ghost.border.right:SetPoint("BOTTOMRIGHT", 0, 0)
    ghost.border.right:SetWidth(1)

    -- Text
    local font = C3.UI and C3.UI.Theme and C3.UI.Theme.Font or "Fonts\\FRIZQT__.TTF"
    ghost.text = ghost:CreateFontString(nil, "OVERLAY")
    ghost.text:SetFont(font, 10, "")
    ghost.text:SetPoint("CENTER", 0, 0)
    ghost.text:SetTextColor(1, 1, 1)

    ghost:Hide()
    DragFeedback.ghostFrame = ghost
    return ghost
end

-------------------------------------------------------------------------------
-- Insert Indicator (vertical line between tabs)
-------------------------------------------------------------------------------

local function CreateInsertIndicator()
    if DragFeedback.insertIndicator then
        return DragFeedback.insertIndicator
    end

    local indicator = CreateFrame("Frame", "Commander3InsertIndicator", UIParent)
    indicator:SetFrameStrata("TOOLTIP")
    indicator:SetFrameLevel(999)
    indicator:SetSize(4, 20)

    -- Main line (nord8)
    indicator.line = indicator:CreateTexture(nil, "OVERLAY")
    indicator.line:SetColorTexture(0.53, 0.75, 0.82, 1.0)
    indicator.line:SetAllPoints()

    -- Glow effect (nord10, more transparent)
    indicator.glow = indicator:CreateTexture(nil, "BACKGROUND")
    indicator.glow:SetColorTexture(0.37, 0.51, 0.68, 0.4)
    indicator.glow:SetPoint("TOPLEFT", -3, 3)
    indicator.glow:SetPoint("BOTTOMRIGHT", 3, -3)

    indicator:Hide()
    DragFeedback.insertIndicator = indicator
    return indicator
end

-------------------------------------------------------------------------------
-- Drop Highlight (border around target window)
-------------------------------------------------------------------------------

local function CreateDropHighlight()
    if DragFeedback.dropHighlight then
        return DragFeedback.dropHighlight
    end

    local highlight = CreateFrame("Frame", "Commander3DropHighlight", UIParent)
    highlight:SetFrameStrata("DIALOG")
    highlight:SetFrameLevel(998)

    -- Semi-transparent fill (nord10)
    highlight.fill = highlight:CreateTexture(nil, "BACKGROUND")
    highlight.fill:SetColorTexture(0.37, 0.51, 0.68, 0.15)
    highlight.fill:SetAllPoints()

    -- Glowing border (nord8)
    local borderColor = { 0.53, 0.75, 0.82, 0.9 }
    local borderSize = 2

    highlight.top = highlight:CreateTexture(nil, "OVERLAY")
    highlight.top:SetColorTexture(unpack(borderColor))
    highlight.top:SetPoint("TOPLEFT", 0, 0)
    highlight.top:SetPoint("TOPRIGHT", 0, 0)
    highlight.top:SetHeight(borderSize)

    highlight.bottom = highlight:CreateTexture(nil, "OVERLAY")
    highlight.bottom:SetColorTexture(unpack(borderColor))
    highlight.bottom:SetPoint("BOTTOMLEFT", 0, 0)
    highlight.bottom:SetPoint("BOTTOMRIGHT", 0, 0)
    highlight.bottom:SetHeight(borderSize)

    highlight.left = highlight:CreateTexture(nil, "OVERLAY")
    highlight.left:SetColorTexture(unpack(borderColor))
    highlight.left:SetPoint("TOPLEFT", 0, 0)
    highlight.left:SetPoint("BOTTOMLEFT", 0, 0)
    highlight.left:SetWidth(borderSize)

    highlight.right = highlight:CreateTexture(nil, "OVERLAY")
    highlight.right:SetColorTexture(unpack(borderColor))
    highlight.right:SetPoint("TOPRIGHT", 0, 0)
    highlight.right:SetPoint("BOTTOMRIGHT", 0, 0)
    highlight.right:SetWidth(borderSize)

    highlight:Hide()
    DragFeedback.dropHighlight = highlight
    return highlight
end

-------------------------------------------------------------------------------
-- Public API
-------------------------------------------------------------------------------

---Start drag feedback
---@param dragType string "tab" or "window"
---@param label string Initial label text
function DragFeedback:Start(dragType, label)
    if self.active then return end

    self.active = true
    self.dragType = dragType

    -- Create frames if needed
    local ghost = CreateGhostFrame()
    local indicator = CreateInsertIndicator()
    local highlight = CreateDropHighlight()

    -- Set initial label
    ghost.text:SetText(label or "Dragging")
    ghost.bg:SetColorTexture(unpack(COLORS.neutral))

    -- Size ghost to fit text
    local textWidth = ghost.text:GetStringWidth()
    ghost:SetWidth(math.max(80, textWidth + 20))

    ghost:Show()
end

---Update drag feedback (called every frame)
---@param state table?
function DragFeedback:Update(state)
    if not self.active then return end

    local ghost = self.ghostFrame
    if not ghost then return end
    if not state then return end

    -- Get cursor position
    local cursorX, cursorY = state.cursorX, state.cursorY
    if not cursorX or not cursorY then
        local scale = UIParent:GetEffectiveScale()
        cursorX, cursorY = GetCursorPosition()
        cursorX, cursorY = cursorX / scale, cursorY / scale
    end

    -- Position ghost near cursor
    ghost:ClearAllPoints()
    ghost:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", cursorX + 15, cursorY - 5)

    local action = state.action or "neutral"
    local label = state.label or "Dragging"
    local targetWindow = state.targetWindow
    local insertPosition = state.insertPosition

    -- Update ghost appearance
    local color = COLORS[action] or COLORS.neutral
    ghost.bg:SetColorTexture(unpack(color))
    ghost.text:SetText(label)

    -- Size ghost to fit text
    local textWidth = ghost.text:GetStringWidth()
    ghost:SetWidth(math.max(80, textWidth + 20))

    -- Update drop highlight
    self:UpdateDropHighlight(targetWindow, action)

    -- Update insert indicator
    self:UpdateInsertIndicator(targetWindow, insertPosition)

end

---Update drop highlight position
---@param targetWindow table?
---@param action string?
function DragFeedback:UpdateDropHighlight(targetWindow, action)
    local highlight = self.dropHighlight
    if not highlight then return end

    local anchor, isTabBar = getHighlightAnchor(targetWindow)
    if anchor then
        highlight:ClearAllPoints()
        highlight:SetPoint("TOPLEFT", anchor, "TOPLEFT", 0, 0)
        highlight:SetPoint("BOTTOMRIGHT", anchor, "BOTTOMRIGHT", 0, 0)
        applyHighlightColor(highlight, COLORS[action] or COLORS.neutral, isTabBar)
        highlight:Show()
    else
        highlight:Hide()
    end
end

---Update insert indicator position
---@param targetWindow table?
---@param insertPosition number?
function DragFeedback:UpdateInsertIndicator(targetWindow, insertPosition)
    local indicator = self.insertIndicator
    if not indicator then return end

    if not targetWindow or not insertPosition or not targetWindow.tabs then
        indicator:Hide()
        return
    end

    -- Don't show insert indicator for windows with hidden tab bars (single-tab)
    if not targetWindow.tabBar or not targetWindow.tabBar:IsShown() then
        indicator:Hide()
        return
    end

    local tabStrip = targetWindow.tabs
    local tabs = tabStrip.tabs

    -- Find X position for indicator
    local indicatorX

    if insertPosition <= 1 then
        -- Before first tab
        if tabs[1] and tabs[1].button then
            indicatorX = tabs[1].button:GetLeft()
        end
    elseif insertPosition > #tabs then
        -- After last tab
        if tabs[#tabs] and tabs[#tabs].button then
            indicatorX = tabs[#tabs].button:GetRight()
        end
    else
        -- Between tabs
        local prevTab = tabs[insertPosition - 1]
        local nextTab = tabs[insertPosition]
        if prevTab and prevTab.button and nextTab and nextTab.button then
            local prevRight = prevTab.button:GetRight()
            local nextLeft = nextTab.button:GetLeft()
            indicatorX = (prevRight + nextLeft) / 2
        end
    end

    if indicatorX then
        -- Get tab bar Y position
        local tabBtn = tabs[1] and tabs[1].button
        if tabBtn then
            local top = tabBtn:GetTop()
            local bottom = tabBtn:GetBottom()

            indicator:ClearAllPoints()
            indicator:SetPoint("TOP", UIParent, "BOTTOMLEFT", indicatorX, top + 2)
            indicator:SetHeight((top - bottom) + 4)
            indicator:Show()
        else
            indicator:Hide()
        end
    else
        indicator:Hide()
    end
end

---Stop drag feedback
function DragFeedback:Stop()
    self.active = false

    -- Hide all frames
    if self.ghostFrame then
        self.ghostFrame:Hide()
    end
    if self.insertIndicator then
        self.insertIndicator:Hide()
    end
    if self.dropHighlight then
        self.dropHighlight:Hide()
    end
end

---Check if drag feedback is active
---@return boolean
function DragFeedback:IsActive()
    return self.active
end

return DragFeedback
