--[[
    Data/Enums.lua

    Central enumerations. Every token the data layer compares against is
    defined here exactly once, so no module ever contains a bare string like
    "Midnight" or "FEROCITY".

    All of these are addon-owned tokens, not Blizzard constants. Display names
    go through Localization; the tokens themselves are never shown.

    Adding an expansion, a specialization, a source type or a requirement kind
    is a single entry here plus its localization key. No other file changes.
]]

local _, ns = ...

ns.Data = ns.Data or {}
local Data = ns.Data

--- Builds a token table (`T.FOO == "FOO"`) plus a membership set for the
--- validator, from an ordered definition list.
local function BuildEnum(definitions)
    local tokens, valid, ordered = {}, {}, {}

    for index, entry in ipairs(definitions) do
        local token = entry.token

        tokens[token] = token
        valid[token] = true

        entry.order = entry.order or index
        ordered[#ordered + 1] = entry
    end

    return tokens, valid, ordered
end

--=============================================================================
-- Expansions
--=============================================================================

Data.Expansion, Data.validExpansions, Data.expansionList = BuildEnum({
    { token = "CLASSIC",       nameKey = "EXPANSION_CLASSIC" },
    { token = "TBC",           nameKey = "EXPANSION_TBC" },
    { token = "WOTLK",         nameKey = "EXPANSION_WOTLK" },
    { token = "CATACLYSM",     nameKey = "EXPANSION_CATACLYSM" },
    { token = "MOP",           nameKey = "EXPANSION_MOP" },
    { token = "WOD",           nameKey = "EXPANSION_WOD" },
    { token = "LEGION",        nameKey = "EXPANSION_LEGION" },
    { token = "BFA",           nameKey = "EXPANSION_BFA" },
    { token = "SHADOWLANDS",   nameKey = "EXPANSION_SHADOWLANDS" },
    { token = "DRAGONFLIGHT",  nameKey = "EXPANSION_DRAGONFLIGHT" },
    { token = "TWW",           nameKey = "EXPANSION_TWW" },
    { token = "MIDNIGHT",      nameKey = "EXPANSION_MIDNIGHT" },
})

--=============================================================================
-- Pet specializations
--=============================================================================

Data.Specialization, Data.validSpecializations, Data.specializationList = BuildEnum({
    { token = "FEROCITY", nameKey = "SPEC_FEROCITY" },
    { token = "TENACITY", nameKey = "SPEC_TENACITY" },
    { token = "CUNNING",  nameKey = "SPEC_CUNNING" },
})

--=============================================================================
-- Where a creature is encountered
--=============================================================================

Data.SourceType, Data.validSourceTypes = BuildEnum({
    { token = "WORLD",   nameKey = "SOURCE_WORLD" },
    { token = "DUNGEON", nameKey = "SOURCE_DUNGEON" },
    { token = "RAID",    nameKey = "SOURCE_RAID" },
    { token = "EVENT",   nameKey = "SOURCE_EVENT" },
    { token = "DELVE",   nameKey = "SOURCE_DELVE" },
})

--=============================================================================
-- Data provenance
--
-- Verified data and development placeholders are never mixed silently. The
-- validator reports the split, and a release may not ship DATA_DEV_SAMPLE
-- records without saying so in the changelog.
--=============================================================================

Data.Source, Data.validSources = BuildEnum({
    { token = "DATA_REAL_VERIFIED" },
    { token = "DATA_DEV_SAMPLE" },
})

--=============================================================================
-- Requirement kinds
--
-- The extensibility point of the requirement system. A requirement is a small
-- record with a `kind` and a free `params` table; the kind declares which
-- params it understands and which of them are mandatory.
--
-- Adding "reputation required" or "phase required" later means adding one
-- entry here. No existing record, index or consumer changes.
--=============================================================================

Data.RequirementKind, Data.validRequirementKinds = BuildEnum({
    { token = "SPEC" },         -- a hunter specialization, e.g. Beast Mastery
    { token = "ITEM" },         -- an item must be held or used
    { token = "SPELL" },        -- a spell must be known
    { token = "QUEST" },        -- a quest must be completed
    { token = "REPUTATION" },   -- a standing with a faction
    { token = "LEVEL" },        -- a minimum character level
    { token = "KNOWLEDGE" },    -- a hunter knowledge unlock
    { token = "INTERACTION" },  -- a special interaction before taming
    { token = "PHASE" },        -- a world state or phase
    { token = "MECHANIC" },     -- an expansion specific mechanic
})

--- Parameter contracts per requirement kind.
-- `params` describes the allowed fields; `required` lists the mandatory ones.
-- A kind with no entry accepts any params and is only checked for its token,
-- which keeps a half-researched requirement expressible without weakening the
-- kinds we do understand.
Data.requirementParams = {
    ITEM       = { params = { itemID = "number", count = "number" }, required = { "itemID" } },
    SPELL      = { params = { spellID = "number" },                  required = { "spellID" } },
    QUEST      = { params = { questID = "number" },                  required = { "questID" } },
    LEVEL      = { params = { level = "number" },                    required = { "level" } },
    REPUTATION = { params = { factionID = "number", standing = "number" }, required = { "factionID" } },
    -- SPEC, KNOWLEDGE, INTERACTION, PHASE and MECHANIC are described by their
    -- localized text until we can verify numeric ids for them.
}

--=============================================================================
-- Coordinates
--
-- CANONICAL FORM: 0..1, matching every current Blizzard map API.
--
--   C_Map.GetPlayerMapPosition       returns 0..1
--   UiMapPoint.CreateFromCoordinates expects 0..1
--
-- Storing 0..100 would mean dividing at every single API boundary and would
-- make an off-by-100 bug invisible in the data. Percentages exist only where a
-- human reads them, and the conversion happens in the UI layer.
--=============================================================================

Data.COORDINATE_MIN = 0
Data.COORDINATE_MAX = 1
