local _, ns = ...

------------------------------------------------------------
-- Gear Tracks: track name -> ordered item levels per rank
------------------------------------------------------------
ns.GEAR_TRACKS = {
    Adventurer = { 220, 224, 227, 230, 233, 237 },
    Veteran    = { 233, 237, 240, 243, 246, 250 },
    Champion   = { 246, 249, 252, 255, 259, 263 },
    Hero       = { 259, 262, 265, 268, 272, 276 },
    Myth       = { 272, 275, 278, 281, 285, 289 },
}

-- Which crest track is used to upgrade each gear track
ns.TRACK_CREST = {
    Adventurer = "Adventurer",
    Veteran    = "Veteran",
    Champion   = "Champion",
    Hero       = "Hero",
    Myth       = "Myth",
}

-- Track ordering (low to high value)
ns.TRACK_ORDER = { "Adventurer", "Veteran", "Champion", "Hero", "Myth" }
ns.TRACK_RANK = {}
for i, t in ipairs(ns.TRACK_ORDER) do
    ns.TRACK_RANK[t] = i
end

------------------------------------------------------------
-- Crafted item level ranges by crest quality
------------------------------------------------------------
ns.CRAFTED_RANGES = {
    Adventurer = { min = 220, max = 233 },
    Veteran    = { min = 233, max = 246 },
    Champion   = { min = 246, max = 259 },
    Hero       = { min = 259, max = 272 },
    Myth       = { min = 272, max = 285 },
}

------------------------------------------------------------
-- Crafting constants
------------------------------------------------------------
ns.CRAFT_CREST_COST = 80              -- crests to craft a spark item (equivalent to 5/6)
ns.VETERAN_EMBELLISH_RESERVE = 160    -- save this many Veteran crests for embellishment crafts

------------------------------------------------------------
-- Key strategic facts
------------------------------------------------------------
-- When you max a lower track, the item auto-promotes to the next track.
-- These ranks are "free" — covered by cheaper crests from the previous track.
-- e.g., maxing Champion gives you Hero 2/6 without spending Hero crests.
ns.TRACK_FREE_RANKS = {
    Veteran    = { count = 1, prevTrack = "Adventurer" },
    Champion   = { count = 2, prevTrack = "Veteran" },
    Hero       = { count = 2, prevTrack = "Champion" },
    Myth       = { count = 2, prevTrack = "Hero" },
}


-- Vault breakpoint value (crests-per-week equivalent bonus)
ns.VAULT_BREAKPOINTS = {
    [3] = 0.40,  -- 3/6 from vault = 40% more crests/week value
    [4] = 0.60,  -- 4/6 from vault = 60% more crests/week value
}

-- Crest save discount is 50% and works for ALL crest types
ns.CREST_SAVE_DISCOUNT = 0.50

------------------------------------------------------------
-- Dungeon loot reference (M+ key level -> loot ilvl, vault ilvl)
------------------------------------------------------------
ns.DUNGEON_LOOT = {
    { key = "Heroic", loot = 230, vault = 243 },
    { key = "M0",     loot = 246, vault = 256 },
    { key = "M2",     loot = 250, vault = 259  },
    { key = "M3",     loot = 250, vault = 259  },
    { key = "M4",     loot = 253, vault = 263  },
    { key = "M5",     loot = 256, vault = 263  },
    { key = "M6",     loot = 259, vault = 266  },
    { key = "M7",     loot = 259, vault = 269  },
    { key = "M8",     loot = 263, vault = 269  },
    { key = "M9",     loot = 263, vault = 269  },
    { key = "M10",    loot = 266, vault = 272  },
    { key = "M11",    loot = 266, vault = 272  },
    { key = "M12",    loot = 266, vault = 272  },
}

------------------------------------------------------------
-- Raid reference anchors
------------------------------------------------------------
ns.RAID_TRACKS = {
    Normal  = "Champion",
    Heroic  = "Hero",
    Mythic  = "Myth",
}

------------------------------------------------------------
-- Slot priority (higher = more valuable to upgrade)
------------------------------------------------------------
ns.SLOT_PRIORITY = {
    [16] = 5, -- Main Hand (weapon)
    [17] = 5, -- Off Hand (weapon)
    [5]  = 4, -- Chest
    [7]  = 4, -- Legs
    [1]  = 4, -- Helm
    [13] = 4, -- Trinket 1
    [14] = 4, -- Trinket 2
    [3]  = 3, -- Shoulder
    [10] = 3, -- Hands
    [8]  = 3, -- Feet
    [11] = 3, -- Ring 1
    [12] = 3, -- Ring 2
    [2]  = 2, -- Neck
    [6]  = 2, -- Waist
    [15] = 2, -- Back
    [9]  = 2, -- Wrist
}

------------------------------------------------------------
-- Crest value tiers (higher = more precious, spend carefully)
------------------------------------------------------------
ns.CREST_VALUE = {
    Adventurer = 1,
    Veteran    = 2,
    Champion   = 3,
    Hero       = 4,
    Myth       = 5,
}

------------------------------------------------------------
-- Player profiles (3 tiers matching real progression paths)
------------------------------------------------------------
ns.PROFILES = {
    {
        id = "normal",
        name = "Normal",
        desc = "Casual / Delves / M+ up to 8",
        maxKeyLevel = 8,
        raidTier = "Normal",
        preciousCrests = { "Champion", "Hero", "Myth" },
        freeCrests = { "Adventurer", "Veteran" },
        -- Content drops up to Champion track from M+8 end-of-dungeon
        -- Hero from vault at M+6-8
        farmableTrack = "Champion",
    },
    {
        id = "heroic",
        name = "Heroic",
        desc = "Heroic Raid / M+ 10",
        maxKeyLevel = 10,
        raidTier = "Heroic",
        preciousCrests = { "Hero", "Myth" },
        freeCrests = { "Adventurer", "Veteran", "Champion" },
        -- Hero drops from heroic raid + M+10 end-of-dungeon
        -- Myth from vault only (~1/week)
        farmableTrack = "Hero",
    },
    {
        id = "mythic",
        name = "Mythic",
        desc = "Mythic Raid / M+ 10+",
        maxKeyLevel = 12,
        raidTier = "Mythic",
        preciousCrests = { "Myth" },
        freeCrests = { "Adventurer", "Veteran", "Champion", "Hero" },
        -- Myth drops from mythic raid + high M+ vault
        -- Hero is plentiful
        farmableTrack = "Myth",
    },
}

------------------------------------------------------------
-- Helpers: look up track from item level
------------------------------------------------------------
function ns:GetTrackFromIlvl(ilvl)
    -- Walk tracks from highest to lowest, return first match
    for i = #ns.TRACK_ORDER, 1, -1 do
        local track = ns.TRACK_ORDER[i]
        local levels = ns.GEAR_TRACKS[track]
        if ilvl >= levels[1] and ilvl <= levels[#levels] then
            return track
        end
    end
    return nil
end

function ns:GetRankInTrack(track, ilvl)
    local levels = ns.GEAR_TRACKS[track]
    if not levels then return nil, nil end
    for i, lvl in ipairs(levels) do
        if ilvl == lvl then
            return i, #levels
        end
    end
    return nil, #levels
end

function ns:GetMaxIlvlForTrack(track)
    local levels = ns.GEAR_TRACKS[track]
    if levels then
        return levels[#levels]
    end
    return 0
end

function ns:GetCurrentProfile()
    local profileId = YippYappHelperDB and YippYappHelperDB.profile or "heroic"
    -- Migration: map old profile IDs to new ones
    local migration = {
        casual = "normal", heroic_raider = "heroic", mythic_raider = "mythic",
        mplus_mid = "normal", mplus_high = "heroic", alt = "normal",
    }
    if migration[profileId] then
        profileId = migration[profileId]
        if YippYappHelperDB then YippYappHelperDB.profile = profileId end
    end
    for _, profile in ipairs(ns.PROFILES) do
        if profile.id == profileId then
            return profile
        end
    end
    return ns.PROFILES[2] -- default heroic
end

function ns:IsCrestPrecious(crestTrack)
    local profile = ns:GetCurrentProfile()
    for _, t in ipairs(profile.preciousCrests) do
        if t == crestTrack then return true end
    end
    return false
end

function ns:IsCrestFree(crestTrack)
    local profile = ns:GetCurrentProfile()
    for _, t in ipairs(profile.freeCrests) do
        if t == crestTrack then return true end
    end
    return false
end

------------------------------------------------------------
-- UI scaling: calculate frame sizes based on screen space
------------------------------------------------------------
local TARGET_W = 960
local TARGET_H = 580
local SIDE_PANEL_W = 190  -- progression crest sources panel

function ns:GetAppFrameSize()
    local screenW = GetScreenWidth()
    local screenH = GetScreenHeight()

    -- Max width: leave room for side panel + edges (80% of screen)
    local maxW = math.floor(screenW * 0.80) - SIDE_PANEL_W
    -- Max height: 85% of screen
    local maxH = math.floor(screenH * 0.85)

    local w = math.min(TARGET_W, math.max(maxW, 700))
    local h = math.min(TARGET_H, math.max(maxH, 450))

    return w, h
end

function ns:GetUIScale()
    local w = ns:GetAppFrameSize()
    return w / TARGET_W
end

------------------------------------------------------------
-- Shared visual helpers (inspired by Plumber addon)
------------------------------------------------------------

-- Consistent text color hierarchy
ns.COLORS = {
    TEXT_PRIMARY   = { 0.92, 0.92, 0.92 },  -- near white, main text
    TEXT_SECONDARY = { 0.55, 0.55, 0.55 },  -- medium gray, descriptions
    TEXT_TERTIARY  = { 0.35, 0.35, 0.35 },  -- dark gray, hints/disabled
    TEXT_HEADER    = { 0.70, 0.70, 0.70 },  -- section headers
    ACCENT_GREEN   = { 0.0, 1.0, 0.3 },
    ACCENT_GOLD    = { 1.0, 0.82, 0.0 },
}

-- Disable texture sharpening for smooth edges at any scale
function ns.DisableSharpening(texture)
    if texture.SetTexelSnappingBias then
        texture:SetTexelSnappingBias(0)
    end
    if texture.SetSnapToPixelGrid then
        texture:SetSnapToPixelGrid(false)
    end
end

-- Apply smooth anti-aliased look to a BackdropTemplate frame's border textures
function ns.SmoothFrame(frame)
    for _, region in pairs({ frame:GetRegions() }) do
        if region:IsObjectType("Texture") then
            ns.DisableSharpening(region)
        end
    end
end

-- Apply text shadow for depth
function ns.ApplyTextShadow(fontString)
    fontString:SetShadowColor(0, 0, 0, 0.8)
    fontString:SetShadowOffset(1, -1)
end

-- Create a smooth ADD-blend highlight on a frame (replaces flat color hovers)
function ns.AddGlowHighlight(frame, alpha)
    local hl = frame:CreateTexture(nil, "HIGHLIGHT")
    hl:SetAllPoints()
    hl:SetColorTexture(1, 1, 1, alpha or 0.06)
    hl:SetBlendMode("ADD")
    return hl
end

------------------------------------------------------------
-- Shared underline-style tab (matches Loot Browser)
-- Returns a button with .label (FontString) and .selectedBar (Texture)
-- Active color: { r, g, b } used for underline + text when selected
------------------------------------------------------------
function ns.CreateUnderlineTab(parent, text, activeColor)
    local btn = CreateFrame("Button", nil, parent)
    btn:SetHeight(24)
    btn:EnableMouse(true)

    local lbl = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    lbl:SetPoint("CENTER", 0, 0)
    lbl:SetText(text)
    lbl:SetTextColor(unpack(ns.COLORS.TEXT_SECONDARY))
    ns.ApplyTextShadow(lbl)
    btn.label = lbl

    local sel = btn:CreateTexture(nil, "ARTWORK")
    sel:SetPoint("BOTTOMLEFT", btn, "BOTTOMLEFT", 2, 0)
    sel:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -2, 0)
    sel:SetHeight(2)
    sel:SetColorTexture(activeColor[1], activeColor[2], activeColor[3], 1)
    sel:Hide()
    btn.selectedBar = sel

    local hl = btn:CreateTexture(nil, "HIGHLIGHT")
    hl:SetAllPoints()
    hl:SetColorTexture(1, 1, 1, 0.04)
    hl:SetBlendMode("ADD")

    btn.activeColor = activeColor
    return btn
end

function ns.SetTabActive(tab)
    tab.selectedBar:Show()
    tab.label:SetTextColor(tab.activeColor[1], tab.activeColor[2], tab.activeColor[3])
end

function ns.SetTabInactive(tab)
    tab.selectedBar:Hide()
    tab.label:SetTextColor(unpack(ns.COLORS.TEXT_SECONDARY))
end

-- Smooth fade-in for a frame (call on OnEnter, auto-stops)
function ns.FadeIn(frame, duration)
    duration = duration or 0.12
    frame._fadeAlpha = frame:GetAlpha()
    frame:SetAlpha(0)
    frame:Show()
    local elapsed = 0
    frame:SetScript("OnUpdate", function(self, dt)
        elapsed = elapsed + dt
        local progress = math.min(elapsed / duration, 1)
        self:SetAlpha(progress)
        if progress >= 1 then
            self:SetScript("OnUpdate", nil)
        end
    end)
end
