local sharedNitro = ac.connect({
  ac.StructItem.key('btm_nitro_audio_v1'),
  nitroPressCounter = ac.StructItem.int32(),
  nitroActive       = ac.StructItem.int32(),
  nitroTimeLeft     = ac.StructItem.double(),
  nitroDuration     = ac.StructItem.double(),
  nitroUsesLeft     = ac.StructItem.int32(),
}, true, ac.SharedNamespace.CarScript)

local displaySize = vec2(1024, 512)

-------------------------------------------------------
-- BAR LAYOUT
-------------------------------------------------------
local margin = 135
local barHeight = 65
local barWidth  = displaySize.x - (margin * 2)
local barPos    = vec2(margin, displaySize.y - barHeight - 20)

-------------------------------------------------------
-- EMPTY TEXT
-------------------------------------------------------
local emptyText = "Nitrous Empty"
local emptyTextPos = vec2(430, 430)
local emptyTextArea = vec2(400, 80)
local emptyTextCentered = false
local emptyTextSize = 42

-------------------------------------------------------
-- AC FONT SETTINGS
-------------------------------------------------------
local AC_FONT_NAME = "MOTEC_Arial_MT"
local BASE_LETTER = vec2(34, 64)
local posScale = 1.10
local lapScale = 1.10
local posBoxPos  = vec2(-275, 188)
local posBoxSize = vec2(1024, 90)
local lapBoxPos  = vec2(110,  188)
local lapBoxSize = vec2(1024, 90)
local POS_FIELD_CHARS = 5
local BOLD_STEPS = 2.5
local BOLD_STEP  = 1
-- =============================================

-------------------------------------------------------
-- COLORS
-------------------------------------------------------
local teal  = rgbm(38/255, 175/255, 234/255, 1.0)
local green = rgbm(0.10, 0.90, 0.10, 1.0)
local red   = rgbm(1.00, 0.10, 0.10, 1.0)
local black = rgbm(0.00, 0.00, 0.00, 1.0)
local outline = rgbm(1.00, 1.00, 1.00, 0.20)
local textWhite  = rgbm(0.65, 0.65, 0.65, 0.2)
local textRed    = rgbm(1.00, 0.10, 0.10, 1.0)
local textShadow = rgbm(0.00, 0.00, 0.00, 0.80)

local TOTAL_USES = 3
local TIME_EPS   = 0.010

-------------------------------------------------------
-- HELPERS
-------------------------------------------------------
local function clamp01(x)
  if x < 0 then return 0 end
  if x > 1 then return 1 end
  return x
end

local function safeDuration()
  local d = tonumber(sharedNitro.nitroDuration) or 0
  if d <= 0.0001 then return 0.0001 end
  return d
end

local function pushACFontSafe(name)
  return pcall(ui.pushACFont, name)
end

local function popACFontSafe()
  pcall(ui.popACFont)
end

local function drawTextWithShadow(text, pos, fontSize, color)
  ui.drawText(text, pos + vec2(2, 2), textShadow, fontSize)
  ui.drawText(text, pos, color, fontSize)
end

local function drawCenteredTextInBox(text, boxPos, boxSize, fontSize, color)
  local ts = ui.measureText(text, fontSize)
  local p = boxPos + vec2((boxSize.x - ts.x) * 0.5, (boxSize.y - ts.y) * 0.5)
  drawTextWithShadow(text, p, fontSize, color)
end

-------------------------------------------------------
-- THICC STAMPING
-------------------------------------------------------
local function stampACTextThicc(text, letter, color, basePos)
  ui.setCursor(basePos)
  ui.acText(text, letter, 0, color, 0, true)

  local steps = math.max(0, math.floor(BOLD_STEPS or 0))
  if steps <= 0 then return end

  local stepPx = math.max(1, math.floor(BOLD_STEP or 1))

  for i = 1, steps do
    local s = i * stepPx

    ui.setCursor(basePos + vec2( s, 0)); ui.acText(text, letter, 0, color, 0, true)
    ui.setCursor(basePos + vec2(-s, 0)); ui.acText(text, letter, 0, color, 0, true)
    ui.setCursor(basePos + vec2(0,  s)); ui.acText(text, letter, 0, color, 0, true)
    ui.setCursor(basePos + vec2(0, -s)); ui.acText(text, letter, 0, color, 0, true)
    ui.setCursor(basePos + vec2( s,  s)); ui.acText(text, letter, 0, color, 0, true)
    ui.setCursor(basePos + vec2(-s,  s)); ui.acText(text, letter, 0, color, 0, true)
    ui.setCursor(basePos + vec2( s, -s)); ui.acText(text, letter, 0, color, 0, true)
    ui.setCursor(basePos + vec2(-s, -s)); ui.acText(text, letter, 0, color, 0, true)
  end
end

-------------------------------------------------------
-- TEXT DRAWING
-------------------------------------------------------
local function drawCenteredAC(text, boxPos, boxSize, scale, color)
  local letter = BASE_LETTER * scale
  local w = (#text) * letter.x
  local h = letter.y
  local p = boxPos + vec2((boxSize.x - w) * 0.5, (boxSize.y - h) * 0.5)

  if not pushACFontSafe(AC_FONT_NAME) then return end
  stampACTextThicc(text, letter, color, p)
  popACFontSafe()
end

local function drawLeftFieldAC(text, boxPos, boxSize, scale, color)
  local letter = BASE_LETTER * scale
  local fieldW = POS_FIELD_CHARS * letter.x
  local x = boxPos.x + (boxSize.x - fieldW) * 0.5
  local y = boxPos.y + (boxSize.y - letter.y) * 0.5

  if not pushACFontSafe(AC_FONT_NAME) then return end
  stampACTextThicc(text, letter, color, vec2(x, y))
  popACFontSafe()
end

-------------------------------------------------------
-- POSITION + LAP/TIME
-------------------------------------------------------
local function getCarsCount()
  local active = 0
  for _, _car in ac.iterateCars.ordered() do
    active = active + 1
  end
  if active > 0 then return active end

  local sim = ac.getSim()
  return math.max(1, sim and sim.carsCount or 1)
end

local function normalizePosition(p, totalCars)
  if p == nil then return nil end
  p = math.floor(tonumber(p) or -999)

  if p >= 0 and p <= totalCars - 1 then
    return p + 1
  end

  if p >= 1 and p <= totalCars then
    return p
  end

  return nil
end

local function getPlayerPosition(totalCars)
  local rt = normalizePosition(ac.getCarRealTimeLeaderboardPosition(0), totalCars)
  if rt then return rt end

  local car0 = ac.getCar(0)
  return normalizePosition(car0 and car0.racePosition, totalCars) or 1
end

local function getCurrentLapDisplay()
  local car0 = ac.getCar(0)
  if not car0 then return 1 end
  local lap = (car0.sessionLapCount or 0) + 1
  if lap < 1 then lap = 1 end
  return lap
end

local function formatMMSS_fromMs(ms)
  local totalSec = math.max(0, math.floor((ms or 0) / 1000 + 0.5))
  local m = math.floor(totalSec / 60)
  local s = totalSec - m * 60
  return string.format("%d:%02d", m, s)
end

local function getSessionSafe(index)
  local ok, sess = pcall(ac.getSession, index)
  if ok then return sess end
  return nil
end

local function getTimedRemainingMs(sim, sess)
  local tl = tonumber(sim and sim.sessionTimeLeft) or -1
  if tl >= 0 then
    if tl > 0 then
      return tl
    end
    local dm = tonumber(sess and sess.durationMinutes) or 0
    if dm > 0 then return 0 end
  end
  return nil
end

local function getLapOrTimeString()
  local sim = ac.getSim()
  local lapNow = getCurrentLapDisplay()

  if not sim then
    return string.format("%d", lapNow)
  end

  local stype = sim.raceSessionType
  local sess = getSessionSafe(sim.currentSessionIndex)

  if stype == ac.SessionType.Practice or stype == ac.SessionType.Qualify then
    local dm = tonumber(sess and sess.durationMinutes) or 0
    local tl = tonumber(sim.sessionTimeLeft) or -1
    local isTimed = (dm > 0) or (tl >= 0)
    if isTimed then
      local ms = getTimedRemainingMs(sim, sess)
      if ms ~= nil then
        return formatMMSS_fromMs(ms)
      end
    end
    return string.format("%d", lapNow)
  end

  if stype == ac.SessionType.Race then
    local isTimedRace = (sess and sess.isTimedRace) == true or (tonumber(sess and sess.durationMinutes) or 0) > 0
    if isTimedRace then
      local ms = getTimedRemainingMs(sim, sess)
      if ms ~= nil then
        return formatMMSS_fromMs(ms)
      end
      return "0:00"
    end

    -- Lap race
    local totalLaps = tonumber(sess and sess.laps) or 0
    if totalLaps > 0 then
      return string.format("%d/%d", lapNow, totalLaps)
    end

    return string.format("%d", lapNow)
  end

  return string.format("%d", lapNow)
end


-------------------------------------------------------
-- ONLINE RACE PRE-START: BLANK ONLY LAP/TIME FIELD
-- (keeps position + nitro bar visible)
-------------------------------------------------------
local function blankLapTimeForOnlineRacePrestart(str)
  local ok, out = pcall(function()
    local sim = ac.getSim()
    if not sim then return str end
    if sim.isOnlineRace == true and sim.raceSessionType == ac.SessionType.Race then
      local tStart = tonumber(sim.timeToSessionStart) or -1
      if tStart > 0 then return "" end
    end
    return str
  end)
  if ok then return out end
  return str
end

-------------------------------------------------------
--COLOR STAGES
-------------------------------------------------------
local function colorsForSpent(spent)
  if spent <= 0 then return teal, green, true end
  if spent == 1 then return teal, green, false end
  if spent == 2 then return green, red, false end
  if spent == 3 then return red, black, false end
  return nil, black, false
end

function script.update(dt)
  local usesLeft = tonumber(sharedNitro.nitroUsesLeft)
  local active   = (tonumber(sharedNitro.nitroActive) or 0) ~= 0
  local timeLeft = tonumber(sharedNitro.nitroTimeLeft) or 0.0
  local duration = safeDuration()

  if usesLeft == nil or usesLeft < 0 or usesLeft > TOTAL_USES then
    usesLeft = TOTAL_USES
  end

  local spent = TOTAL_USES - usesLeft
  if spent < 0 then spent = 0 end
  if spent > TOTAL_USES then spent = TOTAL_USES end

  local rectPos  = barPos
  local rectSize = vec2(barWidth, barHeight)

  if usesLeft == 0 and (not active) then
    ui.drawRectFilled(rectPos, rectPos + rectSize, black)
    ui.drawRect(rectPos, rectPos + rectSize, outline)

    if emptyTextCentered then
      drawCenteredTextInBox(emptyText, emptyTextPos, emptyTextArea, emptyTextSize, textRed)
    else
      drawTextWithShadow(emptyText, emptyTextPos, emptyTextSize, textRed)
    end

    local totalCars = getCarsCount()
    local pos = getPlayerPosition(totalCars)
    local posStr = string.format("%d/%d", pos, totalCars)
    local lapOrTimeStr = blankLapTimeForOnlineRacePrestart(getLapOrTimeString())

    drawLeftFieldAC(posStr, posBoxPos, posBoxSize, posScale, textWhite)
    drawCenteredAC(lapOrTimeStr, lapBoxPos, lapBoxSize, lapScale, textWhite)
    return
  end

  local topColor, backingColor, startFullTop = colorsForSpent(spent)

  ui.drawRectFilled(rectPos, rectPos + rectSize, backingColor)

  local topW = 0.0
  if active then
    topW = barWidth * clamp01(timeLeft / duration)
    if timeLeft <= TIME_EPS then topW = 0.0 end
  else
    topW = startFullTop and barWidth or 0.0
  end

  if topColor and topW > 0 then
    ui.drawRectFilled(rectPos, rectPos + vec2(topW, barHeight), topColor)
  end

  ui.drawRect(rectPos, rectPos + rectSize, outline)

  local totalCars = getCarsCount()
  local pos = getPlayerPosition(totalCars)
  local posStr = string.format("%d/%d", pos, totalCars)
  local lapOrTimeStr = blankLapTimeForOnlineRacePrestart(getLapOrTimeString())

  drawLeftFieldAC(posStr, posBoxPos, posBoxSize, posScale, textWhite)
  drawCenteredAC(lapOrTimeStr, lapBoxPos, lapBoxSize, lapScale, textWhite)
end