-- merged_cluster.lua — cluster UI + bars (no outlines, no G-force)

sim = ac.getSim()

--══════════════════════════════════════════════════════════════════════════════
--  cluster_plus_bars.lua — Combines cluster UI + masked alpha bar + dual bars
--  Notes:
--    - Single `update(dt)` entrypoint draws everything.
--    - No outlines on bars. G-force removed.
--══════════════════════════════════════════════════════════════════════════════

---------------------------------- USER SETTINGS ------------------------------
-- Speed / range
local useMph = false           -- false = km/h, true = mph
local fuelKmsPerLitre = 9      -- km per litre for the range readout

-- Temperature decimal dot adjustments (pixels; negative pulls dot left / closer)
local AMBIENT_DOT_SHIFT = 20
local WATER_DOT_SHIFT   = 20
local OIL_DOT_SHIFT     = 20

-- Temperature decimals shown (e.g. 1 => “85.3”)
local TEMP_DECIMALS = 0

-- Tyre readout positions (edit to taste)
local TYRE_P_FONT  = "mg"
local TYRE_T_FONT  = "mg"
local TYRE_P_SIZE  = vec2(40, 80)    -- pressure text size
local TYRE_T_SIZE  = vec2(40, 80)    -- temperature text size
local TYRE_P_COLOR = rgbm(1,1,1,1)
local TYRE_T_COLOR = rgbm(1,1,1,1)

-- FL / FR / RL / RR positions (pressures)
local POS_P_FL = vec2( 300, 1520)
local POS_P_FR = vec2(1680, 1520)
local POS_P_RL = vec2( 300, 1700)
local POS_P_RR = vec2(1680, 1700)

-- FL / FR / RL / RR positions (temperatures)
local POS_T_FL = vec2( 300, 1588)
local POS_T_FR = vec2(1680, 1588)
local POS_T_RL = vec2( 300, 1768)
local POS_T_RR = vec2(1680, 1768)

---------------------------------- DISPLAY COLOURS ----------------------------
local white = rgbm(1, 1, 1,1)

---------------------------------- GEAR MAPS ----------------------------------
local gearT = { [-1]="R",[0]="N",[1]="1",[2]="2",[3]="3",[4]="4",[5]="5",[6]="6",[7]="7",[8]="8" }
local gearM = { [0]="N", [1]="D",[2]="D",[3]="D",[4]="4",[5]="5",[6]="6",[7]="7",[8]="8" }

---------------------------------- HELPERS ------------------------------------
local function v(str) local x,y=str:match("([^,]+),%s*([^,]+)"); return vec2(tonumber(x), tonumber(y)) end
local function clamp(val,a,b) return (val<a) and a or (val>b) and b or val end

-- Draw one decimal number with a movable dot (closer/tighter kerning)
-- pos = where the INTEGER part is anchored (alignment/width apply to that)
local function drawTightDecimal(value, decimals, pos, letter, font, color, align, width, spacing, dotShiftPx)
  local s = string.format("%."..tostring(decimals or 1).."f", value or 0)
  local intPart, decPart = s:match("^(%-?%d+)%.(%d+)$")
  if not intPart then intPart, decPart = tostring(math.floor(tonumber(value or 0)+0.5)), "0" end

  -- draw integer (normal)
  display.text{
    text = intPart,
    pos = pos,
    letter = letter,
    font = font,
    color = color,
    alignment = align or 0.5,
    width = width or 0,
    spacing = spacing or 0
  }

  -- measure approx digit advance as a fraction of letter.x (works well with mono-ish cluster fonts)
  local adv = letter.x * 0.4
  -- anchor for dot: start at end of intPart then add dotShiftPx
  local dotX = pos.x + (adv * #intPart) + (dotShiftPx or 0)
  local dotPos = vec2(dotX, pos.y)

  -- dot
  display.text{
    text = ".",
    pos = dotPos,
    letter = letter,
    font = font,
    color = color,
    alignment = 0, width = 0,
    spacing = spacing or 0
  }

  -- decimals: nudge a little after the dot
  local decPos = vec2(dotPos.x + (letter.x * 0.6), pos.y)
  display.text{
    text = decPart,
    pos = decPos,
    letter = letter,
    font = font,
    color = color,
    alignment = 0, width = 0,
    spacing = spacing or 0
  }
end

---------------------------------- RECT DRAW HELPER ---------------------------
local function rect(x,y,w,h,c,opacity)
  display.rect{ pos=vec2(x,y), size=vec2(w,h), color=c, opacity=opacity or 1 }
end

---------------------------------- MASKED ALPHA FILL (kept for your bar) ------
local ENABLE_MASKED_ALPHA_BAR = true
local ALPHA_MASK_PATH = "cluster/urus_cluster_mask.png"
local BAR_POS  = vec2(0, 0)
local BAR_SIZE = vec2(0, 0)
local BAR_FADE = 8

local _maskTex = nil
local function maskTex()
  if _maskTex ~= nil then return _maskTex end
  local ok, tex = pcall(function() return display.loadTexture(ALPHA_MASK_PATH) end)
  _maskTex = ok and tex or false
  return _maskTex
end
local function drawAlphaFillBar(pos, size, fraction, fadePx)
  local w = math.floor(size.x * clamp(fraction or 0, 0, 1) + 0.5)
  if w <= 0 then return end
  local fade = math.max(tonumber(fadePx) or 0, 0)
  local solidW = math.max(w - fade, 0)
  if solidW > 0 then display.rect{ pos = pos, size = vec2(solidW, size.y), color = rgb(0,0,0), opacity = 1 } end
  local rest = w - solidW
  if rest > 0 then
    local slices = math.max(math.ceil(rest / 4), 4)
    local segW   = rest / slices
    for i = 0, slices - 1 do
      local a  = (i + 1) / slices
      local sx = pos.x + solidW + math.floor(i * segW + 0.5)
      local sw = math.ceil(segW)
      if sw > 0 then display.rect{ pos = vec2(sx, pos.y), size = vec2(sw, size.y), color = rgb(0,0,0), opacity = a } end
    end
  end
end
local function drawMaskedAlphaFillBar(pos, size, fraction, fadePx)
  local tex = maskTex()
  if not tex then return drawAlphaFillBar(pos, size, fraction, fadePx) end
  local f = clamp(fraction or 0, 0, 1); if f <= 0 then return end
  local filledPx = size.x * f
  display.image{ texture = tex, pos = pos, size = vec2(filledPx, size.y), uvStart = vec2(0,0), uvEnd = vec2(f,1), color = rgbm(0,0,0,1) }
  local fade = math.max(tonumber(fadePx) or 0, 0)
  if fade > 0 then
    local fadeW  = math.min(fade, filledPx)
    local slices = math.max(math.ceil(fadeW / 4), 4)
    local segW   = fadeW / slices
    for i = 0, slices - 1 do
      local segPx0 = filledPx - fadeW + i * segW
      local segPx1 = segPx0 + segW
      local uv0 = segPx0 / size.x
      local uv1 = segPx1 / size.x
      local sx = pos.x + segPx0
      local sw = segW
      local a  = 1 - (i + 1) / slices
      display.image{ texture = tex, pos = vec2(sx, pos.y), size = vec2(sw, size.y), uvStart = vec2(uv0,0), uvEnd = vec2(uv1,1), color = rgbm(0,0,0,a) }
    end
  end
end
local function alphaBarFraction()
  if car and car.maxFuel and car.maxFuel > 0 then return math.max(0, math.min(1, (car.fuel or 0) / car.maxFuel)) end
  return 0
end

--══════════════════════════════════════════════════════════════════════════════
--            761              BAR CONFIG (Fuel smooth + Turbo boxes)
--══════════════════════════════════════════════════════════════════════════════

-- Fuel bar (reusing old oil bar area). No outlines.
local BAR_FUEL = { x = 761, y = 655, w = 464, h = 31 }
local FUEL_BG_COLOR   = rgb(0.3, 0.3, 0.3)
local FUEL_FILL_COLOR = rgb(1.00, 1, 1)

-- Turbo bar config (keep discrete boxes but no outlines)
local BAR_TURBO= { x = 1465, y = 1241, w = 150, h = 11 }
local TURBO_FILL_MODE   = "left"
local TURBO_BOXES_TOTAL = 12
local TURBO_BOXES_HALF  = 5
local TURBO_GAP_PX      = 1
local TURBO_COL_EDGE1   = rgb(1.00, 0.25, 0.00)
local TURBO_COL_EDGE2   = rgb(1.00, 0.25, 0.00)
local TURBO_COL_MID     = rgb(1.00, 0.25, 0.00)
local TURBO_SPLIT1      = 0.50
local TURBO_SPLIT2      = 0.50

-- Draw N boxes across a span (no outline)
local function drawBoxesSpan(x0, wSpan, boxes, gap, fromLeft, lit, height, colorByIndex, baseY)
  if boxes <= 0 or wSpan <= 0 then return end
  local totalGap = gap * (boxes - 1)
  local boxW = (wSpan - totalGap) / boxes
  if boxW <= 0 then return end
  for i = 1, boxes do
    if i <= lit then
      local x = fromLeft and (x0 + (i-1)*(boxW+gap)) or (x0 + wSpan - i*boxW - (i-1)*gap)
      rect(x, baseY, boxW, height, colorByIndex(i, boxes))
    end
  end
end
local function colorAtFracTurbo(frac)
  if frac <= TURBO_SPLIT1 then return TURBO_COL_EDGE1
  elseif frac <= TURBO_SPLIT2 then return TURBO_COL_EDGE2
  else return TURBO_COL_MID end
end
local function drawBarDiscrete(box, mode, boxesHalf, boxesTotal, gapPx, progress, colorFunc)
  progress = clamp(progress or 0, 0, 1)
  if mode == "both" then
    local halfW = box.w * 0.5
    local litHalf = math.floor(progress * boxesHalf + 1e-6)
    drawBoxesSpan(box.x, halfW, boxesHalf, gapPx, true,  litHalf, box.h, function(i,n) return colorFunc((i-0.5)/n) end, box.y)
    drawBoxesSpan(box.x + halfW, halfW, boxesHalf, gapPx, false, litHalf, box.h, function(i,n) return colorFunc((i-0.5)/n) end, box.y)
  else
    local lit = math.floor(progress * boxesTotal + 1e-6)
    drawBoxesSpan(box.x, box.w, boxesTotal, gapPx, mode=="left", lit, box.h, function(i,n) return colorFunc((i-0.5)/n) end, box.y)
  end
end

-- Turbo source
local function getTurboFrac()
  local f = 0
  if car then
    if car.turboBoost ~= nil then f = car.turboBoost
    elseif car.boostRatio ~= nil then f = car.boostRatio
    elseif car.boostPressure ~= nil and car.maxBoostPressure ~= nil then f = (car.boostPressure) / math.max(0.001, car.maxBoostPressure)
    end
  end
  return clamp(f, 0, 1)
end

--══════════════════════════════════════════════════════════════════════════════
--                         TYRE HELPERS (pressure & temp)
--══════════════════════════════════════════════════════════════════════════════
local function readWheel(i)
  local st = (ac and ac.getCarState) and ac.getCarState(0) or nil
  local w = (st and st.wheels and st.wheels[i]) or nil
  if not w then return { pres=0, temp=0 } end
  local p = w.tyrePressure or w.tyrePressureKpa or 0
  -- auto-convert to bar if looks like kPa
  if p > 10 then p = p * 0.01 end
  local t = w.tyreCoreTemperature or w.tyreSurfaceTemperature or w.tyreContactTemperature or 0
  return { pres = p, temp = t }
end

--══════════════════════════════════════════════════════════════════════════════
--                                   UPDATE
--══════════════════════════════════════════════════════════════════════════════
local function cluster_update(dt)
  -- Live values
  local speedKmh = car.speedKmh
  local speedVal = useMph and (speedKmh / 1.609344) or speedKmh

  local timeText   = string.format("%02d:%02d", sim.timeHours, sim.timeMinutes)
  local timeText2  = string.format("%02d:%02d", sim.timeHours, sim.timeMinutes)
  local speedText  = tostring(math.floor(speedVal))
  local tempAmbient  = sim.ambientTemperature
  local gearText   = gearT[car.gear]
  local rangeText  = tostring(math.floor(car.fuel * fuelKmsPerLitre))
  local totalText  = string.format("%1d", car.distanceDrivenTotalKm)
  local sessText   = string.format("%1d", car.distanceDrivenSessionKm)
  local waterText  = string.format("%1d", car.waterTemperature)
  local oilText  = string.format("%1d", car.oilTemperature)

  -- >>> Only change here: use raw number so drawTightDecimal formats it <<<
  local waterValue = (car.waterTemperature or 0)
  local oilValue   = (car.oilTemperature or 0)

  -- 🕒 TIME
  display.text({ text = timeText, pos = v("33.5, 641.8"), letter = v("80, 200"),
    font = "porschechrono", color = 1, alignment = 0.9, width = 0, spacing = -1 })


  -- 📏 TOTAL KM
  display.text({ text = totalText, pos = v("790, 1924"), letter = v("55, 110"),
    font = 'fonts/porsche_next', color = white, alignment = 1, width = 250, spacing =0 })

  -- 📏 SESSION KM
  display.text({ text = sessText, pos = v("850, 1830"), letter = v("55, 110"),
    font = 'fonts/porsche_next', color = white, alignment = 1, width = 250, spacing =0 })

  -- 🛣 RANGE
  display.text({ text = rangeText, pos = v("1240, 638"), letter = v("35, 70"),
    font ='fonts/porsche_next', color = white, alignment = 1, width = 155, spacing = -1 })

  -- 🛣 water
  display.text({ text = waterText, pos = v("1120, 265"), letter = v("65, 130"),
    font ="mg", color = white, alignment = 1, width = 155, spacing = -1 })

  -- 🛣 oil
  display.text({ text = oilText, pos = v("1120, 105"), letter = v("65, 130"),
    font ="mg", color = white, alignment = 1, width = 155, spacing = -1 })

  -- 🌡 AMBIENT TEMP (tight dot)
  drawTightDecimal(tempAmbient, TEMP_DECIMALS, v("910, 793"), v("35, 70"), 'fonts/porsche_next', white, 0.5, 250, -5, AMBIENT_DOT_SHIFT)



-- drs ready

  if not car.extraA then display.text({ text = "DRS", pos = v("1130, 1580"), letter = v("50, 100"),
    font ='fonts/porsche_next', color = white, alignment = 1, width = 0, spacing = -1 })
end

  if not car.extraA then display.text({ text = " ready", pos = v("1280, 1580"), letter = v("50, 100"),
    font ='fonts/porsche_next', color = white, alignment = 1, width = 0, spacing = -12})
end


-- drs active

  if car.extraA then display.text({ text = "DRS", pos = v("1130, 1580"), letter = v("50, 100"),
    font ='fonts/porsche_next', color = rgbm (0,1,0,1), alignment = 1, width = 0, spacing = -1 })
end

  if car.extraA then display.text({ text = "act", pos = v("1320, 1580"), letter = v("50, 100"),
    font ='fonts/porsche_next', color = rgbm (0,1,0,1), alignment = 1, width = 0, spacing = -12})
end
  if car.extraA then display.text({ text = "   ive", pos = v("1318, 1580"), letter = v("50, 100"),
    font ='fonts/porsche_next', color = rgbm (0,1,0,1), alignment = 1, width = 0, spacing = -15})
end

  -- Dyn text
 display.text({ text = "Dyn", pos = v("820, 1580"), letter = v("50, 100"),
    font ='fonts/porsche_next', color = white, alignment = 1, width = 0, spacing = -1 })

  -- Dyn dot text
  display.text({ text = ".", pos = v("950, 1580"), letter = v("50, 100"),
    font ='fonts/porsche_next', color = white, alignment = 1, width = 0, spacing = -1 })





  -- 🛢 OIL PRESSURE 
  local oilPresBar = (car.oilPressure or 0)
  if oilPresBar > 10 then oilPresBar = oilPresBar * 0.01 end   -- if kPa-like, convert to bar
  display.text({ text = string.format("%.1f", oilPresBar), pos = v("1088, 425.2"), letter = v("65, 130"),
    font = "mg", color = white, alignment = 0.5, width = 250, spacing = -30 })

  --═══════════════════════ Masked Alpha Bar (if used) ════════════════════════
  if ENABLE_MASKED_ALPHA_BAR then
    drawMaskedAlphaFillBar(BAR_POS, BAR_SIZE, alphaBarFraction(), BAR_FADE)
  end

  --═══════════════════════ Smooth Fuel Bar ═══════════════════════════════════
  local fuelFrac = (car and car.maxFuel and car.maxFuel > 0) and clamp((car.fuel or 0) / car.maxFuel, 0, 1) or 0
  rect(BAR_FUEL.x, BAR_FUEL.y, BAR_FUEL.w, BAR_FUEL.h, FUEL_BG_COLOR, 1)      -- background
  local fillW = BAR_FUEL.w * fuelFrac
  if fillW > 0.5 then rect(BAR_FUEL.x, BAR_FUEL.y, fillW, BAR_FUEL.h, FUEL_FILL_COLOR, 1) end

  --═══════════════════════ Turbo spool bar (boxes, no outline) ═══════════════
  local turboF = getTurboFrac()
  drawBarDiscrete(BAR_TURBO, TURBO_FILL_MODE, TURBO_BOXES_HALF, TURBO_BOXES_TOTAL, TURBO_GAP_PX, turboF, colorAtFracTurbo)

  --═══════════════════════ Tyres: pressures (bar) & temps (°C) ═══════════════
  local fl = readWheel(0)  -- FL
  local fr = readWheel(1)  -- FR
  local rl = readWheel(2)  -- RL
  local rr = readWheel(3)  -- RR

end

function update(dt)
  cluster_update(dt)
end
