--[[
    Data.lua - TGXG Interrupt
    -----------------------------------------------------------------------
    Spec-first data architecture (pattern taken from BliZzi Party Tools).

    Single source of truth: TGX.SPEC_REGISTRY — one record per WoW spec ID
    describing that spec's interrupt. Every other lookup table is compiled
    from this registry at load time. To add/change a spell: edit the
    registry only.
    -----------------------------------------------------------------------
]]

TGX = TGX or {}

------------------------------------------------------------
-- Class colours (r, g, b)
------------------------------------------------------------
TGX.CLASS_COLORS = {
    DEATHKNIGHT = { 0.77, 0.12, 0.23 },
    DEMONHUNTER = { 0.64, 0.19, 0.79 },
    DRUID       = { 1.00, 0.49, 0.04 },
    EVOKER      = { 0.20, 0.58, 0.50 },
    HUNTER      = { 0.67, 0.83, 0.45 },
    MAGE        = { 0.41, 0.80, 0.94 },
    MONK        = { 0.00, 1.00, 0.59 },
    PALADIN     = { 0.96, 0.55, 0.73 },
    PRIEST      = { 1.00, 1.00, 1.00 },
    ROGUE       = { 1.00, 0.96, 0.41 },
    SHAMAN      = { 0.00, 0.44, 0.87 },
    WARLOCK     = { 0.58, 0.51, 0.79 },
    WARRIOR     = { 0.78, 0.61, 0.43 },
}

------------------------------------------------------------
-- Spec Registry (single source of truth)
--   class    WoW class token
--   spellID  primary interrupt spell ID
--   name     spell display name (English fallback; localized at runtime)
--   cd       base cooldown in seconds
--   icon     texture file ID
--   noKick   true = spec has no interrupt
--   isPet    true = interrupt is cast by a pet
------------------------------------------------------------
local SPEC_REGISTRY = {
    -------------------- Death Knight --------------------
    [250] = { class="DEATHKNIGHT", spellID=47528,  name="Mind Freeze",       cd=15, icon=237527 },
    [251] = { class="DEATHKNIGHT", spellID=47528,  name="Mind Freeze",       cd=15, icon=237527 },
    [252] = { class="DEATHKNIGHT", spellID=47528,  name="Mind Freeze",       cd=15, icon=237527 },
    -------------------- Demon Hunter --------------------
    [577]  = { class="DEMONHUNTER", spellID=183752, name="Disrupt",          cd=15, icon=1305153 },
    [581]  = { class="DEMONHUNTER", spellID=183752, name="Disrupt",          cd=15, icon=1305153 },
    [1480] = { class="DEMONHUNTER", spellID=183752, name="Disrupt",          cd=15, icon=1305153 },
    -------------------- Druid --------------------
    [102] = { class="DRUID", spellID=78675,  name="Solar Beam",              cd=45, icon=252188 },
    [103] = { class="DRUID", spellID=106839, name="Skull Bash",              cd=15, icon=236946 },
    [104] = { class="DRUID", spellID=106839, name="Skull Bash",              cd=15, icon=236946 },
    [105] = { class="DRUID", noKick=true },
    -------------------- Evoker --------------------
    [1467] = { class="EVOKER", spellID=351338, name="Quell",                 cd=18, icon=4622469 },
    [1468] = { class="EVOKER", noKick=true },  -- Midnight: Preservation lost Quell
    [1473] = { class="EVOKER", spellID=351338, name="Quell",                 cd=18, icon=4622469 },
    -------------------- Hunter --------------------
    [253] = { class="HUNTER", spellID=147362, name="Counter Shot",           cd=24, icon=249170  },
    [254] = { class="HUNTER", spellID=147362, name="Counter Shot",           cd=24, icon=249170  },
    [255] = { class="HUNTER", spellID=187707, name="Muzzle",                 cd=15, icon=1376045 },
    -------------------- Mage --------------------
    [62]  = { class="MAGE", spellID=2139, name="Counterspell",               cd=25, icon=135856  },
    [63]  = { class="MAGE", spellID=2139, name="Counterspell",               cd=25, icon=135856  },
    [64]  = { class="MAGE", spellID=2139, name="Counterspell",               cd=25, icon=135856  },
    -------------------- Monk --------------------
    [268] = { class="MONK", spellID=116705, name="Spear Hand Strike",        cd=15, icon=608940  },
    [269] = { class="MONK", spellID=116705, name="Spear Hand Strike",        cd=15, icon=608940  },
    [270] = { class="MONK", noKick=true }, -- Mistweaver
    -------------------- Paladin --------------------
    [65]  = { class="PALADIN", noKick=true }, -- Holy
    [66]  = { class="PALADIN", spellID=96231, name="Rebuke",                 cd=15, icon=523893  },
    [70]  = { class="PALADIN", spellID=96231, name="Rebuke",                 cd=15, icon=523893  },
    -------------------- Priest --------------------
    [256] = { class="PRIEST", noKick=true },
    [257] = { class="PRIEST", noKick=true },
    [258] = { class="PRIEST", spellID=15487, name="Silence",                 cd=30, icon=458230  },
    -------------------- Rogue --------------------
    [259] = { class="ROGUE", spellID=1766, name="Kick",                      cd=15, icon=132219  },
    [260] = { class="ROGUE", spellID=1766, name="Kick",                      cd=15, icon=132219  },
    [261] = { class="ROGUE", spellID=1766, name="Kick",                      cd=15, icon=132219  },
    -------------------- Shaman --------------------
    [262] = { class="SHAMAN", spellID=57994, name="Wind Shear",              cd=12, icon=136018  },
    [263] = { class="SHAMAN", spellID=57994, name="Wind Shear",              cd=12, icon=136018  },
    [264] = { class="SHAMAN", spellID=57994, name="Wind Shear",              cd=30, icon=136018  }, -- Resto: 30s
    -------------------- Warlock --------------------
    [265] = { class="WARLOCK", spellID=19647,  name="Spell Lock",            cd=24, icon=136174, isPet=true, petSpellID=19647 },
    [266] = { class="WARLOCK", spellID=119914, name="Axe Toss",              cd=30, icon=236316, isPet=true, petSpellID=89766 },
    [267] = { class="WARLOCK", spellID=19647,  name="Spell Lock",            cd=24, icon=136174, isPet=true, petSpellID=19647 },
    -------------------- Warrior --------------------
    [71]  = { class="WARRIOR", spellID=6552, name="Pummel", cd=15, icon=132938 },
    [72]  = { class="WARRIOR", spellID=6552, name="Pummel", cd=15, icon=132938 },
    [73]  = { class="WARRIOR", spellID=6552, name="Pummel", cd=15, icon=132938 },
}
TGX.SPEC_REGISTRY = SPEC_REGISTRY

-- Classes that keep their interrupt even as healer spec
TGX.HEALER_KEEPS_KICK = { SHAMAN = true }

------------------------------------------------------------
-- Compiler: derive lookup tables from SPEC_REGISTRY.
-- Two phases because pairs() order is non-deterministic — the class
-- default must be fully resolved before overrides can be computed.
------------------------------------------------------------
local allSpells    = {}
local classDefault = {}
local specOverride = {}
local specNoKick   = {}
local classHasNoKick = {}

for specID, spec in pairs(SPEC_REGISTRY) do
    if spec.noKick then
        specNoKick[specID] = true
    else
        if not allSpells[spec.spellID] then
            allSpells[spec.spellID] = { name = spec.name, cd = spec.cd, icon = spec.icon }
        end
        local cur = classDefault[spec.class]
        if not cur or (spec.cd < cur.cd and not spec.isPet) then
            classDefault[spec.class] = { id = spec.spellID, cd = spec.cd, icon = spec.icon }
        end
    end
end

for specID, spec in pairs(SPEC_REGISTRY) do
    if not spec.noKick then
        local def = classDefault[spec.class]
        if def and (spec.spellID ~= def.id or spec.cd ~= def.cd) then
            specOverride[specID] = { id = spec.spellID, cd = spec.cd, icon = spec.icon, isPet = spec.isPet }
        end
    end
    if spec.noKick and spec.class and classDefault[spec.class] then
        classHasNoKick[spec.class] = true
    end
end

TGX.ALL_INTERRUPTS        = allSpells
TGX.CLASS_INTERRUPTS      = classDefault
TGX.SPEC_OVERRIDES        = specOverride
TGX.SPEC_NO_INTERRUPT     = specNoKick
TGX.CLASS_HAS_NOKICK_SPEC = classHasNoKick

-- String-keyed mirror for taint-safe lookups (WoW 12.x secret values:
-- a tainted number can't index a table, but its tostring() often can
-- after laundering — see TGX.Taint in Core.lua).
TGX.ALL_INTERRUPTS_STR = {}
for id, v in pairs(allSpells) do TGX.ALL_INTERRUPTS_STR[tostring(id)] = v end

-- Name-keyed lookup (UNIT_SPELLCAST events sometimes only yield a clean
-- localized name; rebuilt with localized names in Core:Initialize).
TGX.ALL_INTERRUPTS_BY_NAME = {}
for id, v in pairs(allSpells) do
    TGX.ALL_INTERRUPTS_BY_NAME[v.name] = { id = id, cd = v.cd }
end

------------------------------------------------------------
-- CC fallback abilities per class: stuns/incapacitates/fears that also
-- STOP an interruptible cast. Suggested by the kick alert while the own
-- interrupt is on cooldown. Order = suggestion priority (most reliable
-- first); entries the character hasn't learned are skipped at runtime,
-- names/icons resolve localized via C_Spell.
------------------------------------------------------------
TGX.CC_FALLBACKS = {
    WARRIOR     = { 107570, 46968, 5246 },        -- Storm Bolt, Shockwave, Intimidating Shout
    PALADIN     = { 853, 115750 },                -- Hammer of Justice, Blinding Light
    DEATHKNIGHT = { 221562, 207167 },             -- Asphyxiate, Blinding Sleet
    DEMONHUNTER = { 179057, 217832, 202137 },     -- Chaos Nova, Imprison, Sigil of Silence
    DRUID       = { 5211, 99, 132469 },           -- Mighty Bash, Incapacitating Roar, Typhoon
    EVOKER      = { 368970, 357214 },             -- Tail Swipe, Wing Buffet
    HUNTER      = { 19577, 186387 },              -- Intimidation, Bursting Shot
    MAGE        = { 31661, 118 },                 -- Dragon's Breath, Polymorph
    MONK        = { 119381, 115078, 116844 },     -- Leg Sweep, Paralysis, Ring of Peace
    PRIEST      = { 8122, 64044 },                -- Psychic Scream, Psychic Horror
    ROGUE       = { 408, 1833, 2094, 1776 },      -- Kidney Shot, Cheap Shot, Blind, Gouge
    SHAMAN      = { 51514, 192058 },              -- Hex, Capacitor Totem
    WARLOCK     = { 30283, 6789, 5782 },          -- Shadowfury, Mortal Coil, Fear
}

------------------------------------------------------------
-- Raid target markers
------------------------------------------------------------
TGX.MARKER_NAMES = {
    [1] = { en = "Star",     de = "Stern"    },
    [2] = { en = "Circle",   de = "Kreis"    },
    [3] = { en = "Diamond",  de = "Diamant"  },
    [4] = { en = "Triangle", de = "Dreieck"  },
    [5] = { en = "Moon",     de = "Mond"     },
    [6] = { en = "Square",   de = "Quadrat"  },
    [7] = { en = "Cross",    de = "Kreuz"    },
    [8] = { en = "Skull",    de = "Totenkopf"},
}

-- Assignment order for "Automatische Einteilung": first member with an
-- interrupt gets Triangle, second Moon, third Star, ... (user-requested
-- order: Dreieck, Mond, Stern; then the remaining marks).
TGX.ASSIGN_MARKER_ORDER = { 4, 5, 1, 6, 2, 7, 3, 8 }

------------------------------------------------------------
-- SavedVariables defaults
------------------------------------------------------------
TGX.DEFAULTS = {
    -- Tracker window
    trackerEnabled   = true,
    locked           = false,
    scale            = 100,      -- percent
    barWidth         = 220,
    barHeight        = 26,
    barGap           = 2,
    growUpward       = false,
    showOwnBar       = true,
    showTitle        = true,
    fontSize         = 12,
    posX             = 0,        -- offset from UIParent CENTER
    posY             = 120,
    classColorBars   = true,
    hideOutOfGroup   = false,    -- hide tracker while solo (test mode overrides)

    -- Blizzard cast-bar manager: the ORIGINAL TargetFrameSpellBar /
    -- FocusFrameSpellBar stay in charge of rendering; the addon only
    -- makes them freely placeable and scalable. HasPos=false = the bar
    -- sits at Blizzard's default anchor until the user drags its mover.
    castbarEnabled      = true,
    castbarFocus        = true,      -- also manage the focus spell bar
    castbarLocked       = true,
    castbarScale        = 100,       -- target bar scale in percent
    castbarFocusScale   = 100,
    -- Width/height overrides in pixels; 0 = Blizzard's original size.
    castbarBarWidth       = 0,
    castbarBarHeight      = 0,
    castbarFocusBarWidth  = 0,
    castbarFocusBarHeight = 0,
    castbarHasPos       = false,
    castbarPosX         = 0,
    castbarPosY         = -180,
    castbarFocusHasPos  = false,
    castbarFocusPosX    = 0,
    castbarFocusPosY    = -240,

    -- Kick alert (target / focus)
    kickAlertEnabled = true,
    kickAlertFocus   = true,
    kickAlertSound   = true,
    kickAlertUnknown = false,   -- also alert when interrupt-status is secret/unknown
    kickAlertPosY    = 200,
    -- Interruptibility database (seed + self-learning) as fallback when
    -- Midnight hides the notInterruptible flag as a secret value.
    spellDBEnabled   = true,

    -- Own-kick cooldown icon (green glow = ready, gray + countdown = CD).
    -- Own lock, same UX as the cast bars: untick "Kick-Symbol sperren",
    -- drag the green overlay, position is saved.
    kickIconEnabled  = true,
    kickIconLocked   = true,
    kickIconCombatOnly = false,   -- true = only visible while in combat
    kickIconSize     = 64,
    kickIconPosX     = 0,
    kickIconPosY     = -250,

    -- Auto assignment
    autoAssignEnabled  = true,
    assignAnnounceChat = true,   -- post assignment to party chat at key start
    assignAlertSound   = true,
    -- Assignment permissions. Default (both false) = the group LEADER is
    -- the single source of truth — recommended, prevents two users
    -- overwriting each other's assignments.
    assignAllowAssist  = false,  -- raid assistants may also send assignments
    assignAllowAll     = false,  -- everyone may send; last change wins

    -- Kick rotation ("who kicks next"): deterministic kicker order,
    -- advances on every observed kick, synced via addon messages.
    rotationEnabled    = false,

    -- CC fallback: while the own kick is on cooldown, the alert suggests
    -- a ready stun/incapacitate that also stops the cast.
    ccFallbackEnabled  = true,

    -- Interrupt history feed: the last few observed interrupts as a
    -- fading list below the tracker.
    historyFeedEnabled = true,

    -- Fail-kick feedback: own kick without a following interrupt →
    -- red flash on the own tracker bar (+ sound).
    failFeedbackEnabled = true,
    failFeedbackSound   = true,

    -- Minimap button (left: settings, right: lock/unlock all,
    -- shift-left: test mode)
    minimapButton      = true,
    minimapPos         = 220,     -- angle in degrees around the minimap

    -- Settings window: false = normal mode (essentials only, sensible
    -- preconfiguration), true = expert mode (every option visible).
    expertMode         = false,
}
