local _ = ... -- addon name unused

local function normalizeRealm(realm)
  if not realm or realm == "" then return realm end
  return realm:gsub("[%'%-%s]", "")
end

local function unitKey(name, realm)
  if not name or name == "" then return nil end
  realm = realm and realm ~= "" and normalizeRealm(realm) or GetNormalizedRealmName()
  if not realm or realm == "" then return nil end
  return name .. "-" .. realm
end

local function getRegion()
  local region = PvPScoutDB and PvPScoutDB.region
  if region and region ~= "" then return region end
  local portal = GetCVar("portal")
  return portal and string.lower(portal) or "eu"
end

-- Determine display color for a rating with optional top 0.01% override.
-- isTop001: when true, always return orange regardless of rating bands.
local function ratingColor(r, isTop001)
  if not (PvPScoutDB and PvPScoutDB.colorByRating) then
    -- Fixed gray when color-by-rating is disabled
    return 0.8, 0.8, 0.8
  end
  -- Orange override for the very top of the leaderboard
  if isTop001 then return 1.00, 0.50, 0.00 end -- orange
  r = tonumber(r) or 0
  -- Bands as requested:
  -- < 1800 => green, >=1800 => blue, >=2100 => silver, >=2400 => purple
  if r >= 2400 then return 0.64, 0.21, 0.93 end -- purple
  if r >= 2100 then return 0.78, 0.78, 0.78 end -- silver (light gray)
  if r >= 1800 then return 0.00, 0.44, 0.87 end -- blue
  return 0.12, 1.00, 0.00 -- green
end

local function secondsToHuman(secs)
  secs = math.max(0, math.floor(secs or 0))
  local d = math.floor(secs / 86400); secs = secs % 86400
  local h = math.floor(secs / 3600); secs = secs % 3600
  local m = math.floor(secs / 60)
  if d > 0 then return string.format("%dd %dh", d, h) end
  if h > 0 then return string.format("%dh %dm", h, m) end
  return string.format("%dm", m)
end

-- Map specialization IDs to canonical slugs used in Data.lua (locale-agnostic)
local SPEC_ID_TO_SLUG = {
  -- Mage
  [62] = "arcane", [63] = "fire", [64] = "frost",
  -- Paladin
  [65] = "holy", [66] = "protection", [70] = "retribution",
  -- Warrior
  [71] = "arms", [72] = "fury", [73] = "protection",
  -- Druid
  [102] = "balance", [103] = "feral", [104] = "guardian", [105] = "restoration",
  -- Death Knight
  [250] = "blood", [251] = "frost", [252] = "unholy",
  -- Hunter
  [253] = "beast-mastery", [254] = "marksmanship", [255] = "survival",
  -- Priest
  [256] = "discipline", [257] = "holy", [258] = "shadow",
  -- Rogue
  [259] = "assassination", [260] = "outlaw", [261] = "subtlety",
  -- Shaman
  [262] = "elemental", [263] = "enhancement", [264] = "restoration",
  -- Warlock
  [265] = "affliction", [266] = "demonology", [267] = "destruction",
  -- Monk
  [268] = "brewmaster", [269] = "windwalker", [270] = "mistweaver",
  -- Demon Hunter
  [577] = "havoc", [581] = "vengeance",
  -- Evoker
  [1467] = "devastation", [1468] = "preservation", [1473] = "augmentation",
}

local function getCurrentSpecSlug()
  if type(_G.GetSpecialization) == "function" and type(_G.GetSpecializationInfo) == "function" then
    local specIndex = _G.GetSpecialization()
    if specIndex then
      local id, name = _G.GetSpecializationInfo(specIndex)
      if id and SPEC_ID_TO_SLUG[id] then return SPEC_ID_TO_SLUG[id] end
      -- Fallback: slugify localized name in case our data used localized slugs
      if type(name) == "string" then
        return name:lower():gsub("[%".."'".."%p]", ""):gsub("%s+", "-")
      end
    end
  end
  return nil
end

local function addRatingLines(tooltip, key)
  if not key then return end
  local region = getRegion()
  local data = PvPScoutData and PvPScoutData.data and PvPScoutData.data[region]
  local noDataMode = not data

  local selected = PvPScoutDB and PvPScoutDB.brackets or { "2v2", "3v3", "shuffle", "rbg", "blitz" }
  local order = (PvPScoutDB and PvPScoutDB.bracketOrder) or selected
  local inSet = {}
  for _, k in ipairs(selected) do inSet[k] = true end
  local brackets = {}
  for _, k in ipairs(order) do if inSet[k] then table.insert(brackets, k) end end
  if #brackets == 0 then
    -- If user deliberately selected nothing, render only header and return
    if PvPScoutDB and PvPScoutDB.showHeader then
      tooltip:Show()
    end
    return
  end

  local labels = { ["2v2"] = PvPScout_L("B2V2"), ["3v3"] = PvPScout_L("B3V3"), ["shuffle"] = PvPScout_L("B_SHUFFLE"), ["rbg"] = PvPScout_L("B_RBG"), ["blitz"] = PvPScout_L("B_BLITZ") }
  local added = false

  -- Identify whether the tooltip target is the player; we only enforce strict current-spec filtering for self.
  local unitToken = tooltip and tooltip._PvPScout_UnitToken or nil
  local isPlayerUnit = false
  if type(_G.UnitIsUnit) == "function" and unitToken then
    pcall(function() isPlayerUnit = _G.UnitIsUnit(unitToken, "player") end)
  end

  if PvPScoutDB and PvPScoutDB.showHeader then
    local season = PvPScoutData and PvPScoutData.season or 0
    local parts = { PvPScout_L("TITLE_BRACKET_RATING"), string.upper(region) }
    if season and season > 0 then table.insert(parts, "S"..tostring(season)) end
    local header = table.concat(parts, " — ")
    if PvPScoutDB.showUpdatedAt then
      local updatedAt = (PvPScoutData and PvPScoutData.updatedAt) or 0
      if updatedAt > 0 then
        local now = type(_G.time) == "function" and _G.time() or 0
        local age = secondsToHuman(now - updatedAt)
        header = header .. string.format(" — %s", string.format(PvPScout_L("UPDATED_AGO"), age))
      end
    end
    tooltip:AddLine(header, 1, 0.82, 0)
    added = true
    local staleH = (PvPScoutDB and PvPScoutDB.staleHours) or 24
    local updatedAt = (PvPScoutData and PvPScoutData.updatedAt) or 0
    if updatedAt > 0 and staleH and staleH > 0 then
      local now2 = type(_G.time) == "function" and _G.time() or 0
      local ageSecs = now2 - updatedAt
      if ageSecs > staleH * 3600 then
        tooltip:AddLine(PvPScout_L("STALE_NOTICE"), 1, 0.2, 0.2)
      end
    end
  end

  local function computeTrendDelta(bracket, currentRating)
    if not (PvPScoutDB and PvPScoutDB.showTrend) then return nil end
    if not PvPScoutDB.history or not key then return PvPScout_L("TREND_PLACEHOLDER") end
    local list = PvPScoutDB.history[key] and PvPScoutDB.history[key][bracket]
    if not list or #list == 0 then return PvPScout_L("TREND_PLACEHOLDER") end
    local now = type(_G.time) == "function" and _G.time() or 0
    local cutoff = now - (7 * 86400)
    local oldest
    for i = 1, #list do
      if (list[i].ts or 0) >= cutoff then oldest = list[i]; break end
    end
    if not oldest then oldest = list[1] end
    local base = tonumber(oldest.rating) or 0
    local delta = (tonumber(currentRating) or 0) - base
    if delta == 0 then return "+0" end
    if delta > 0 then return "+" .. tostring(delta) end
    return tostring(delta) -- negative already has '-'
  end

  -- Cache per-bracket entry counts for top 0.01% evaluation
  local bracketCounts = {}

  for _, bracket in ipairs(brackets) do
    local v = (not noDataMode) and (data[bracket] and data[bracket][key]) or nil
    local label = labels[bracket] or bracket
    if v then
      -- For Shuffle/Blitz, prefer specialization-aware display when per-spec data are available
      local effective = v
      if (bracket == "shuffle" or bracket == "blitz") and v.bySpec and type(v.bySpec) == "table" then
        if isPlayerUnit then
          -- Strict behavior for the player: show only the current spec's rating
          local currentSpecSlug = getCurrentSpecSlug()
          if currentSpecSlug and v.bySpec[currentSpecSlug] then
            effective = v.bySpec[currentSpecSlug]
          else
            -- No rating for this spec: treat as missing data for this bracket (placeholder)
            effective = nil
          end
        else
          -- For other units, we cannot reliably detect their current spec without an inspect round-trip.
          -- Fall back to the best available spec (by best rank, then highest rating), or the overall value.
          local best
          for _, val in pairs(v.bySpec) do
            if not best then
              best = val
            else
              local br = tonumber(best.rank) or math.huge
              local vr = tonumber(val.rank) or math.huge
              if vr < br then
                best = val
              elseif vr == br then
                local bv = tonumber(best.rating) or 0
                local vv = tonumber(val.rating) or 0
                if vv > bv then best = val end
              end
            end
          end
          effective = best or v
        end
      end
      if not effective then
        -- Show placeholder line when no per-spec rating for the current spec
        local value = PvPScout_L("PLACEHOLDER")
        if PvPScoutDB and PvPScoutDB.showRank then
          value = value .. string.format(" (%s %s)", PvPScout_L("RANK"), PvPScout_L("PLACEHOLDER"))
        end
        if PvPScoutDB and PvPScoutDB.showTrend then
          value = value .. string.format("  [%s %s]", PvPScout_L("TREND"), PvPScout_L("TREND_PLACEHOLDER"))
        end
        tooltip:AddDoubleLine(label, value, 1, 1, 1, 0.8, 0.8, 0.8)
        added = true
      else
        local rating = tonumber(effective.rating) or 0
        local value = tostring(rating)
        local rankNum = tonumber(effective.rank)
      if PvPScoutDB and PvPScoutDB.showRank then
        if rankNum and rankNum > 0 then
          value = value .. string.format(" (%s %s)", PvPScout_L("RANK"), rankNum)
        else
          -- Rank placeholder when rating exists but rank is missing/non-positive
          value = value .. string.format(" (%s %s)", PvPScout_L("RANK"), PvPScout_L("PLACEHOLDER"))
        end
      end
      -- No spec tag in the output per requirements; we only display current spec's rating for Shuffle/Blitz.
  local trend = computeTrendDelta(bracket, rating)
      if trend then
        value = value .. string.format("  [%s %s]", PvPScout_L("TREND"), trend)
      end
      -- Evaluate top 0.01% per bracket (per region), with a minimum of top 1
      local isTop001 = false
      if rankNum and rankNum > 0 and data and data[bracket] then
        local total = bracketCounts[bracket]
        if not total then
          total = 0
          for _ in pairs(data[bracket]) do total = total + 1 end
          bracketCounts[bracket] = total
        end
        if total and total > 0 then
          local topN = math.max(1, math.ceil(total * 0.0001))
          if rankNum <= topN then isTop001 = true end
        end
      end
        local vr, vg, vb = ratingColor(rating, isTop001)
        tooltip:AddDoubleLine(label, value, 1, 1, 1, vr, vg, vb)
        added = true
      end
    else
      -- No ladder data for this bracket: still honor placeholder parity for rank/trend when toggled
      local value = PvPScout_L("PLACEHOLDER")
      if PvPScoutDB and PvPScoutDB.showRank then
        value = value .. string.format(" (%s %s)", PvPScout_L("RANK"), PvPScout_L("PLACEHOLDER"))
      end
      if PvPScoutDB and PvPScoutDB.showTrend then
        value = value .. string.format("  [%s %s]", PvPScout_L("TREND"), PvPScout_L("TREND_PLACEHOLDER"))
      end
      tooltip:AddDoubleLine(label, value, 1, 1, 1, 0.8, 0.8, 0.8)
      added = true
    end
  end
  -- If nothing was added (shouldn't happen when brackets selected), keep tooltip as-is
  if added then tooltip:Show() end
end

local function OnTooltipSetUnit(tooltip)
  if not PvPScoutDB or not PvPScoutDB.enabled then return end
  local _, unit = tooltip:GetUnit()
  if not unit or not UnitIsPlayer(unit) then return end
  local name, realm = UnitName(unit)
  local key = unitKey(name, realm and realm ~= "" and realm or GetNormalizedRealmName())
  -- prevent duplicate additions when multiple hooks fire (ElvUI/TipTac/Blizzard)
  if tooltip._PvPScout_UnitKey == key and tooltip._PvPScout_Added then return end
  tooltip._PvPScout_UnitKey = key
  tooltip._PvPScout_UnitToken = unit
  addRatingLines(tooltip, key)
  tooltip._PvPScout_Added = true
end

local function SetupTooltipHook()
  if _G.PvPScout_TooltipHooked then return end
  -- Always try multiple strategies for maximum compatibility; guard duplicates in OnTooltipSetUnit
  if TooltipDataProcessor and TooltipDataProcessor.AddTooltipPostCall and Enum and Enum.TooltipDataType then
    TooltipDataProcessor.AddTooltipPostCall(Enum.TooltipDataType.Unit, function(tooltip)
      OnTooltipSetUnit(tooltip)
    end)
  end
  if GameTooltip then
    if GameTooltip.HookScript and GameTooltip:HasScript("OnTooltipSetUnit") then
      GameTooltip:HookScript("OnTooltipSetUnit", OnTooltipSetUnit)
    end
    if _G.hooksecurefunc and GameTooltip.SetUnit then
      _G.hooksecurefunc(GameTooltip, "SetUnit", function(self)
        OnTooltipSetUnit(self)
      end)
    end
    -- reset flag when tooltip is cleared to allow future additions
    if GameTooltip.HookScript and GameTooltip:HasScript("OnTooltipCleared") then
      GameTooltip:HookScript("OnTooltipCleared", function(self)
        self._PvPScout_Added = nil
        self._PvPScout_UnitKey = nil
        self._PvPScout_UnitToken = nil
      end)
    end
  end
  _G.PvPScout_TooltipHooked = true
end

-- Defer hook until login to ensure SavedVariables are ready
local hookFrame = CreateFrame("Frame")
hookFrame:RegisterEvent("PLAYER_LOGIN")
hookFrame:SetScript("OnEvent", function()
  SetupTooltipHook()
end)

-- Slash command: /pvpscout [enable|disable|options]
SLASH_PVPSCOUT1 = "/pvpscout"
SlashCmdList["PVPSCOUT"] = function(msg)
  msg = msg and msg:lower() or ""
  if msg:find("disable") then
    PvPScoutDB.enabled = false
    print("PvPScout:", PvPScout_L("MENU_DISABLE"))
    return
  elseif msg:find("enable") then
    PvPScoutDB.enabled = true
    print("PvPScout:", PvPScout_L("MENU_ENABLE"))
    return
  elseif msg == "" or msg:find("option") then
    if type(PvPScout_OpenOptions) == "function" then
      PvPScout_OpenOptions()
    elseif Settings and Settings.OpenToCategory then
      Settings.OpenToCategory("PvPScout")
    else
      InterfaceOptionsFrame_OpenToCategory("PvPScout"); InterfaceOptionsFrame_OpenToCategory("PvPScout")
    end
    return
  end

  local unit = "target"
  if not UnitExists(unit) or not UnitIsPlayer(unit) then
    print("PvPScout:", PvPScout_L("NO_PLAYER_TARGET"))
    return
  end
  local name, realm = UnitName(unit)
  local key = unitKey(name, realm and realm ~= "" and realm or GetNormalizedRealmName())
  local tip = CreateFrame("GameTooltip", "PvPScoutTooltipTemp", UIParent, "GameTooltipTemplate")
  tip:SetOwner(UIParent, "ANCHOR_NONE")
  addRatingLines(tip, key)
  -- Print to chat as well
  local region = getRegion()
  local data = PvPScoutData and PvPScoutData.data and PvPScoutData.data[region]
  if data then
    local labels = { ["2v2"] = PvPScout_L("B2V2"), ["3v3"] = PvPScout_L("B3V3"), ["shuffle"] = PvPScout_L("B_SHUFFLE"), ["rbg"] = PvPScout_L("B_RBG"), ["blitz"] = PvPScout_L("B_BLITZ") }
    local function p(bracket)
      local v = data[bracket] and data[bracket][key]
      if v then
        local label = labels[bracket] or bracket
        local s = label..": "..v.rating
        if PvPScoutDB.showRank then
          local rankNum = tonumber(v.rank)
          if rankNum and rankNum > 0 then
            s = s .. " (" .. PvPScout_L("RANK") .. " " .. rankNum .. ")"
          else
            s = s .. " (" .. PvPScout_L("RANK") .. " " .. PvPScout_L("PLACEHOLDER") .. ")"
          end
        end
        print("PvPScout:", name, s)
      end
    end
    local selected = PvPScoutDB and PvPScoutDB.brackets or { "2v2", "3v3", "shuffle", "rbg", "blitz" }
    for _, k in ipairs(selected) do p(k) end
  end
end
