--[[
    Tracker.lua - TGXG Interrupt
    -----------------------------------------------------------------------
    The interrupt tracker window. Visual layout per row (matching the
    design mock):

      [assigned marker] [spell icon] [ name ............ CD ]
                                      └─ class-colored StatusBar that
                                         drains while the kick is on CD

    * Freely movable while unlocked (drag anywhere on the frame).
    * Scale / bar size configurable through the options window.
    * Own bar shown last (toggleable).
    -----------------------------------------------------------------------
]]

TGX = TGX or {}
TGX.Tracker = TGX.Tracker or {}
local T = TGX.Tracker

local MAX_BARS = 6   -- 5 test-mode members + own bar (live: 4 party + own)
local _bars    = {}
local _frame
local _ticker

local BAR_TEXTURE = "Interface\\BUTTONS\\WHITE8X8"

------------------------------------------------------------
-- Helpers
------------------------------------------------------------
local function db() return TGX.db end

local function ClassColor(class)
    local c = class and TGX.CLASS_COLORS[class]
    if c then return c[1], c[2], c[3] end
    return 0.6, 0.6, 0.6
end

-- Collect display entries: party members first (roster order), own row last.
local function CollectEntries()
    local list = {}
    if TGX.testMode then
        -- Test mode: registry only (fake members), plus own row.
        for name, e in pairs(TGX.Registry:All()) do
            list[#list + 1] = { name = name, entry = e }
        end
        table.sort(list, function(a, b) return a.name < b.name end)
    else
        for i = 1, 4 do
            local u = "party" .. i
            if UnitExists(u) then
                local name = UnitName(u)
                local e = name and TGX.Registry:Get(name)
                if e and e.spellID then
                    list[#list + 1] = { name = name, entry = e }
                end
            end
        end
    end
    if db().showOwnBar and TGX.Self.spellID then
        list[#list + 1] = {
            name  = TGX.Self.name,
            own   = true,
            entry = { class = TGX.Self.class, spellID = TGX.Self.spellID,
                      baseCd = TGX.Self.baseCd, cdEnd = TGX.Self.cdEnd },
        }
    end
    return list
end

------------------------------------------------------------
-- Frame construction
------------------------------------------------------------
local function CreateBar(parent, index)
    local d = db()
    local row = CreateFrame("Frame", nil, parent)
    row:SetSize(d.barWidth, d.barHeight)

    -- Assigned raid marker (left of the row, outside the bar)
    row.marker = row:CreateTexture(nil, "OVERLAY")
    row.marker:SetSize(d.barHeight * 0.7, d.barHeight * 0.7)
    row.marker:SetPoint("LEFT", row, "LEFT", 0, 0)
    row.marker:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons")
    row.marker:Hide()

    -- Assignment status dot: green = marker assigned (active), red = none
    -- (inactive). Sits at the marker slot's bottom edge.
    row.dot = row:CreateTexture(nil, "OVERLAY", nil, 2)
    row.dot:SetSize(9, 9)
    row.dot:SetPoint("BOTTOMLEFT", row, "BOTTOMLEFT", -2, -1)
    row.dot:SetTexture("Interface\\COMMON\\Indicator-Red")

    -- Click-to-assign: invisible button covering the marker slot. Opens
    -- the marker picker for this row's player. Own frame with its own
    -- mouse handling, so it works even while the tracker itself is
    -- locked (the parent frame's EnableMouse only gates dragging).
    row.assignBtn = CreateFrame("Button", nil, row)
    row.assignBtn:SetPoint("TOPLEFT", row, "TOPLEFT", -3, 2)
    row.assignBtn:SetPoint("BOTTOMLEFT", row, "BOTTOMLEFT", -3, -2)
    row.assignBtn:SetWidth(d.barHeight * 0.7 + 6)
    row.assignBtn:SetScript("OnClick", function() T:OpenMarkerPicker(row) end)
    row.assignBtn:SetScript("OnEnter", function(btn)
        GameTooltip:SetOwner(btn, "ANCHOR_LEFT")
        GameTooltip:SetText(TGX.isDE and "Klicken: Symbol zuweisen"
                                      or "Click: assign raid marker", 1, 1, 1)
        GameTooltip:Show()
    end)
    row.assignBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)

    -- Spell icon
    row.icon = row:CreateTexture(nil, "ARTWORK")
    row.icon:SetSize(d.barHeight, d.barHeight)
    row.icon:SetPoint("LEFT", row, "LEFT", d.barHeight * 0.7 + 4, 0)
    row.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)

    -- Status bar (name + CD live on top of it)
    row.bar = CreateFrame("StatusBar", nil, row)
    row.bar:SetPoint("TOPLEFT", row.icon, "TOPRIGHT", 1, 0)
    row.bar:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", 0, 0)
    row.bar:SetStatusBarTexture(BAR_TEXTURE)
    row.bar:SetMinMaxValues(0, 1)
    row.bar:SetValue(1)

    row.bg = row.bar:CreateTexture(nil, "BACKGROUND")
    row.bg:SetAllPoints()
    row.bg:SetColorTexture(0.05, 0.05, 0.05, 0.9)

    row.name = row.bar:CreateFontString(nil, "OVERLAY")
    row.name:SetFont(STANDARD_TEXT_FONT, d.fontSize, "OUTLINE")
    row.name:SetPoint("LEFT", row.bar, "LEFT", 4, 0)
    row.name:SetJustifyH("LEFT")

    row.cd = row.bar:CreateFontString(nil, "OVERLAY")
    row.cd:SetFont(STANDARD_TEXT_FONT, d.fontSize + 2, "OUTLINE")
    row.cd:SetPoint("RIGHT", row.bar, "RIGHT", -4, 0)
    row.cd:SetJustifyH("RIGHT")

    return row
end

function T:Create()
    if _frame then return end
    local d = db()

    _frame = CreateFrame("Frame", "TGXGInterruptTracker", UIParent)
    _frame:SetClampedToScreen(true)
    _frame:SetMovable(true)
    _frame:SetPoint("CENTER", UIParent, "CENTER", d.posX, d.posY)
    _frame:SetScale((d.scale or 100) / 100)

    _frame.title = _frame:CreateFontString(nil, "OVERLAY")
    _frame.title:SetFont(STANDARD_TEXT_FONT, d.fontSize + 1, "OUTLINE")
    _frame.title:SetPoint("BOTTOMLEFT", _frame, "TOPLEFT", 0, 3)
    _frame.title:SetText("|cff33ff99TGXG|r Interrupt")

    -- Settings shortcut: small gear button on the title line (top-right).
    -- Own Button frame → clickable even while the tracker is locked.
    _frame.gear = CreateFrame("Button", nil, _frame)
    _frame.gear:SetSize(16, 16)
    _frame.gear:SetPoint("BOTTOMRIGHT", _frame, "TOPRIGHT", 2, 3)
    local gt = _frame.gear:CreateTexture(nil, "ARTWORK")
    gt:SetAllPoints()
    local gearOk = gt:SetTexture("Interface\\WorldMap\\Gear_64Grey")
    if not (gearOk == true or (gearOk == nil and gt:GetTexture() ~= nil)) then
        gt:SetTexture(136243)   -- engineering cog as fallback
        gt:SetTexCoord(0.08, 0.92, 0.08, 0.92)
    end
    _frame.gear:SetHighlightTexture("Interface\\BUTTONS\\WHITE8X8")
    _frame.gear:GetHighlightTexture():SetVertexColor(0.2, 1.0, 0.6, 0.3)
    _frame.gear:SetScript("OnClick", function()
        if TGX.Options then TGX.Options:Toggle() end
    end)
    _frame.gear:SetScript("OnEnter", function(btn)
        GameTooltip:SetOwner(btn, "ANCHOR_RIGHT")
        GameTooltip:SetText(TGX.isDE and "TGXG-Einstellungen öffnen"
                                      or "Open TGXG settings", 1, 1, 1)
        GameTooltip:Show()
    end)
    _frame.gear:SetScript("OnLeave", function() GameTooltip:Hide() end)

    -- Drag backdrop, only visible while unlocked
    _frame.dragTex = _frame:CreateTexture(nil, "BACKGROUND")
    _frame.dragTex:SetAllPoints()
    _frame.dragTex:SetColorTexture(0.2, 1.0, 0.6, 0.15)
    _frame.dragTex:Hide()

    _frame:SetScript("OnMouseDown", function(f, button)
        if button == "LeftButton" and not db().locked then f:StartMoving() end
    end)
    _frame:SetScript("OnMouseUp", function(f)
        f:StopMovingOrSizing()
        -- Persist as offset from CENTER so scale changes don't shift it.
        local cx, cy = f:GetCenter()
        local ux, uy = UIParent:GetCenter()
        local s = f:GetScale()
        db().posX = (cx * s) - ux
        db().posY = (cy * s) - uy
        f:ClearAllPoints()
        f:SetPoint("CENTER", UIParent, "CENTER", db().posX, db().posY)
    end)

    for i = 1, MAX_BARS do _bars[i] = CreateBar(_frame, i) end

    self:ApplyLock()
    self:Rebuild()

    _ticker = C_Timer.NewTicker(0.1, function() T:UpdateDisplay() end)
end

function T:ApplyLock()
    if not _frame then return end
    local locked = db().locked
    _frame:EnableMouse(not locked)
    _frame.dragTex:SetShown(not locked)
end

------------------------------------------------------------
-- Layout — resolves settings into row geometry.
------------------------------------------------------------
function T:Rebuild()
    if not _frame then return end
    local d = db()
    local entries = CollectEntries()

    _frame:SetScale((d.scale or 100) / 100)
    _frame.title:SetShown(d.showTitle)

    local shown = 0
    for i = 1, MAX_BARS do
        local row = _bars[i]
        local it  = entries[i]
        if it then
            shown = shown + 1
            row.data = it
            row:SetSize(d.barWidth, d.barHeight)
            row.icon:SetSize(d.barHeight, d.barHeight)
            row.marker:SetSize(d.barHeight * 0.7, d.barHeight * 0.7)
            row.icon:SetPoint("LEFT", row, "LEFT", d.barHeight * 0.7 + 4, 0)
            row.name:SetFont(STANDARD_TEXT_FONT, d.fontSize, "OUTLINE")
            row.cd:SetFont(STANDARD_TEXT_FONT, d.fontSize + 2, "OUTLINE")

            row:ClearAllPoints()
            local off = (shown - 1) * (d.barHeight + d.barGap)
            if d.growUpward then
                row:SetPoint("BOTTOMLEFT", _frame, "BOTTOMLEFT", 0, off)
            else
                row:SetPoint("TOPLEFT", _frame, "TOPLEFT", 0, -off)
            end

            local e = it.entry
            -- Spell icon
            local spellData = e.spellID and TGX.ALL_INTERRUPTS[e.spellID]
            row.icon:SetTexture((spellData and spellData.icon) or 134400)

            -- Name (class colored text like the mock's white — keep white,
            -- the bar fill carries the class color)
            row.name:SetText(it.name)

            -- Assigned marker + status dot (green = assigned, red = not)
            local marker = TGX.Assign and TGX.Assign:MarkerFor(it.name)
            if marker then
                SetRaidTargetIconTexture(row.marker, marker)
                row.marker:Show()
                row.dot:SetTexture("Interface\\COMMON\\Indicator-Green")
            else
                row.marker:Hide()
                row.dot:SetTexture("Interface\\COMMON\\Indicator-Red")
            end
            row.assignBtn:SetWidth(d.barHeight * 0.7 + 6)

            -- Bar color
            local r, g, b = ClassColor(e.class)
            if not d.classColorBars then r, g, b = 0.3, 0.8, 1.0 end
            row.bar:SetStatusBarColor(r, g, b, 0.9)

            row:Show()
        else
            row.data = nil
            row:Hide()
        end
    end

    local height = math.max(1, shown * (d.barHeight + d.barGap) - d.barGap)
    _frame:SetSize(d.barWidth, height)

    self:UpdateVisibility()
    self:UpdateDisplay()
end

function T:UpdateVisibility()
    if not _frame then return end
    if TGX.testMode then _frame:Show() return end
    if not db().trackerEnabled then _frame:Hide() return end
    if db().hideOutOfGroup and not IsInGroup() then _frame:Hide() return end
    _frame:Show()
end

function T:Show(force)
    if _frame and (force or db().trackerEnabled) then _frame:Show() end
end

------------------------------------------------------------
-- Marker picker — small flyout next to a tracker row. Click a marker
-- to assign it to that row's player (via TGX.Assign:SetManual), click
-- the red X to clear the assignment. ESC or re-click toggles it away.
------------------------------------------------------------
local _picker

local function BuildPicker()
    _picker = CreateFrame("Frame", "TGXGMarkerPicker", UIParent, "BackdropTemplate")
    _picker:SetFrameStrata("DIALOG")
    _picker:SetClampedToScreen(true)
    _picker:SetSize(4 * 26 + 10, 2 * 26 + 26 + 12)
    _picker:SetBackdrop({
        bgFile   = "Interface\\BUTTONS\\WHITE8X8",
        edgeFile = "Interface\\BUTTONS\\WHITE8X8",
        edgeSize = 1,
    })
    _picker:SetBackdropColor(0.07, 0.07, 0.08, 0.97)
    _picker:SetBackdropBorderColor(0.2, 1.0, 0.6, 0.8)
    _picker:Hide()
    table.insert(UISpecialFrames, "TGXGMarkerPicker")

    for i = 1, 8 do
        local btn = CreateFrame("Button", nil, _picker)
        btn:SetSize(22, 22)
        local col, rowN = (i - 1) % 4, math.floor((i - 1) / 4)
        btn:SetPoint("TOPLEFT", _picker, "TOPLEFT", 6 + col * 26, -6 - rowN * 26)
        btn.tex = btn:CreateTexture(nil, "ARTWORK")
        btn.tex:SetAllPoints()
        btn.tex:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons")
        SetRaidTargetIconTexture(btn.tex, i)
        btn:SetHighlightTexture("Interface\\BUTTONS\\WHITE8X8")
        local hl = btn:GetHighlightTexture()
        hl:SetVertexColor(0.2, 1.0, 0.6, 0.25)
        btn:SetScript("OnClick", function()
            if _picker.playerName then
                TGX.Assign:SetManual(_picker.playerName, i)
            end
            _picker:Hide()
        end)
    end

    local clear = CreateFrame("Button", nil, _picker, "UIPanelButtonTemplate")
    clear:SetSize(4 * 26 - 4, 20)
    clear:SetPoint("BOTTOM", _picker, "BOTTOM", 0, 5)
    clear:SetText(TGX.isDE and "Entfernen" or "Clear")
    clear:SetScript("OnClick", function()
        if _picker.playerName then
            TGX.Assign:SetManual(_picker.playerName, nil)
        end
        _picker:Hide()
    end)
end

function T:OpenMarkerPicker(row)
    if not (row.data and row.data.name) then return end
    if not _picker then BuildPicker() end
    -- Re-click on the same row toggles the picker closed.
    if _picker:IsShown() and _picker.playerName == row.data.name then
        _picker:Hide()
        return
    end
    _picker.playerName = row.data.name
    _picker:ClearAllPoints()
    _picker:SetPoint("RIGHT", row, "LEFT", -6, 0)
    _picker:Show()
end

------------------------------------------------------------
-- Per-tick display update (bar fill + CD number)
------------------------------------------------------------
function T:UpdateDisplay()
    if not (_frame and _frame:IsShown()) then return end
    local now = GetTime()
    for i = 1, MAX_BARS do
        local row = _bars[i]
        local it  = row.data
        if it and row:IsShown() then
            local e = it.entry
            -- Own row reads live state (TGX.Self.cdEnd changes after Rebuild)
            local cdEnd  = it.own and TGX.Self.cdEnd or e.cdEnd or 0
            local baseCd = (it.own and TGX.Self.baseCd) or e.baseCd
                           or (e.spellID and TGX.ALL_INTERRUPTS[e.spellID] and TGX.ALL_INTERRUPTS[e.spellID].cd)
                           or 15
            local remaining = cdEnd - now
            if remaining > 0 and baseCd > 0 then
                row.bar:SetValue(math.max(0, math.min(1, remaining / baseCd)))
                row.cd:SetText(math.ceil(remaining))
                row.cd:SetTextColor(1, 0.82, 0)
            else
                -- Ready: dark bar (fill drained), green "Ready" label —
                -- matches the mock where only members on CD show a fill.
                row.bar:SetValue(0)
                row.cd:SetText(TGX.L.READY)
                row.cd:SetTextColor(0.3, 1, 0.3)
            end
        end
    end
end
