import { useEffect, useMemo, useRef, useState } from 'react'
import { useQuery } from '@tanstack/react-query'
import { LineChart } from 'lucide-react'
import type { Driver, EnrichedResult, EnrichedGrid, PositionSample, Lap, Meeting, Session, Chapter } from '../types'
import { fetchReplayFrames, fetchTrackOutline } from '../api'
import { ReplayTrackMap } from './ReplayTrackMap'
import { ChapterStrip } from './ChapterStrip'
import { EmptyStateCard } from './EmptyStateCard'
import { gridDelta, gridDeltaClass, formatDuration, formatGap } from '../utils'
import {
  chapterBandFill,
  chapterEndScrub,
  chapterStartScrub,
  chapterTourDurations,
  deCollideYPositions,
  decimatedPositionLabels,
} from '../lib/chapters'
import { isReplayMapAvailable } from '../lib/replayMap'
import '../styles/race-story.css'

const CHAPTER_TOUR_MS = 90_000
const CHART_W = 640
const CHART_H = 180
const CHART_PL = 40
const CHART_PR = 48
const CHART_PT = 8
const CHART_PB = 20

interface ChartTiming {
  tMin: number
  tMax: number
  tRange: number
}

interface Props {
  data: {
    results: EnrichedResult[]
    starting_grid: EnrichedGrid[]
    positions: PositionSample[]
    laps: Lap[]
    datasets: Record<string, any>
    race_control?: any[]
    pit_stops?: any[]
    session?: Session
    meeting?: Meeting
    drivers?: Driver[]
    chapters?: Chapter[]
  }
}

/**
 * Position samples are recorded for the entire session, including the pre-race
 * grid period.  Use the winning driver's laps to define the race window so
 * that the x-axis starts at lights-out rather than at the earliest sample.
 */
function raceChartTiming(
  positions: PositionSample[],
  laps: Lap[],
  results: EnrichedResult[],
): ChartTiming | null {
  const positionTimes = positions
    .map((position) => new Date(position.date).getTime())
    .filter(Number.isFinite)
  if (positionTimes.length === 0) return null

  const fallbackMin = Math.min(...positionTimes)
  const fallbackMax = Math.max(...positionTimes)
  const fallback = {
    tMin: fallbackMin,
    tMax: fallbackMax,
    tRange: Math.max(fallbackMax - fallbackMin, 1),
  }

  const winner = results.find((result) => result.position === 1)
  if (!winner) return fallback

  const winnerLaps = laps
    .filter((lap) => lap.driver_number === winner.driver_number && lap.lap_number > 0)
    .map((lap) => ({ ...lap, start: new Date(lap.date_start).getTime() }))
    .filter((lap) => Number.isFinite(lap.start))
    .sort((a, b) => a.lap_number - b.lap_number)
  if (winnerLaps.length === 0) return fallback

  const firstLap = winnerLaps[0]
  const lastLap = winnerLaps[winnerLaps.length - 1]
  const finalLapDuration = lastLap.lap_duration ?? 0
  const tMax = lastLap.start + (finalLapDuration > 0 ? finalLapDuration * 1000 : 0)
  if (tMax <= firstLap.start) return fallback

  return { tMin: firstLap.start, tMax, tRange: tMax - firstLap.start }
}

export function RaceStoryCanvas({ data }: Props) {
  const {
    results,
    starting_grid: grid,
    positions,
    datasets,
    race_control = [],
    pit_stops = [],
    laps = [],
    session,
    meeting,
    drivers = [],
    chapters = [],
  } = data
  const hasPositions = datasets['positions']?.status === 'available'

  const [scrubTime, setScrubTime] = useState<number | null>(null)
  const [hoverDriver, setHoverDriver] = useState<number | null>(null)
  const [mapOpen, setMapOpen] = useState(false)
  const [isPlaying, setIsPlaying] = useState(false)
  const [playbackSpeed, setPlaybackSpeed] = useState(10)
  const [chapterTourActive, setChapterTourActive] = useState(false)
  const [tourChapterIndex, setTourChapterIndex] = useState<number | null>(null)
  const [selectedChapterIndex, setSelectedChapterIndex] = useState<number | null>(null)
  const svgRef = useRef<SVGSVGElement>(null)
  const tourRef = useRef({ chapterIndex: 0, startedAt: 0, durationMs: 0, startScrub: 0, endScrub: 0 })

  const chartTiming = useMemo(() => raceChartTiming(positions, laps, results), [laps, positions, results])
  const hasChartData = hasPositions && chartTiming !== null
  const circuitKey = session?.circuit_key ?? meeting?.circuit_key ?? 0
  const outlineYear = meeting?.year ?? (session?.date_start ? new Date(session.date_start).getFullYear() : 0)
  const canProbeMap = Boolean(session?.session_key) && circuitKey > 0 && outlineYear > 0

  const replayQuery = useQuery({
    queryKey: ['replay-frames', session?.session_key, 5000],
    queryFn: () => fetchReplayFrames(session!.session_key, 5000),
    enabled: canProbeMap,
  })
  const outlineQuery = useQuery({
    queryKey: ['track-outline', circuitKey, outlineYear],
    queryFn: () => fetchTrackOutline(circuitKey, outlineYear),
    enabled: canProbeMap,
  })

  const mapProbeSettled = !canProbeMap || (!replayQuery.isLoading && !outlineQuery.isLoading)
  const mapAvailable = useMemo(
    () =>
      canProbeMap &&
      isReplayMapAvailable(
        replayQuery.data,
        outlineQuery.data,
        replayQuery.isError || outlineQuery.isError,
      ),
    [canProbeMap, outlineQuery.data, outlineQuery.isError, replayQuery.data, replayQuery.isError],
  )
  const showMapPanel = mapOpen && mapAvailable

  useEffect(() => {
    if (!mapAvailable && mapOpen) {
      setMapOpen(false)
    }
  }, [mapAvailable, mapOpen])

  useEffect(() => {
    if (!isPlaying || !chartTiming) return

    let frame = 0
    let last = performance.now()
    const tick = (now: number) => {
      const delta = now - last
      last = now
      setScrubTime((current) => {
        const next = Math.min(1, (current ?? 0) + (delta * playbackSpeed) / chartTiming.tRange)
        if (next >= 1) {
          setIsPlaying(false)
        }
        return next
      })
      frame = requestAnimationFrame(tick)
    }

    frame = requestAnimationFrame(tick)
    return () => cancelAnimationFrame(frame)
  }, [chartTiming, isPlaying, playbackSpeed])

  const stopChapterTour = () => {
    setChapterTourActive(false)
    setTourChapterIndex(null)
  }

  const jumpToChapter = (index: number, scrub: number) => {
    setIsPlaying(false)
    stopChapterTour()
    setSelectedChapterIndex(index)
    setScrubTime(scrub)
  }

  const clearChapterSelection = () => {
    setSelectedChapterIndex(null)
  }

  const toggleChapterTour = () => {
    if (chapterTourActive) {
      stopChapterTour()
      return
    }
    if (!chartTiming || chapters.length === 0) return
    setIsPlaying(false)
    setSelectedChapterIndex(null)
    setChapterTourActive(true)
    setTourChapterIndex(0)
    const startScrub = chapterStartScrub(chapters[0], chartTiming.tMin, chartTiming.tRange) ?? 0
    setScrubTime(startScrub)
    const durations = chapterTourDurations(chapters, CHAPTER_TOUR_MS)
    tourRef.current = {
      chapterIndex: 0,
      startedAt: performance.now(),
      durationMs: durations[0] ?? CHAPTER_TOUR_MS / chapters.length,
      startScrub,
      endScrub: chapterEndScrub(chapters[0], chartTiming.tMin, chartTiming.tRange) ?? startScrub,
    }
  }

  useEffect(() => {
    if (!chapterTourActive || !chartTiming || chapters.length === 0) return

    let frame = 0
    const tick = (now: number) => {
      const state = tourRef.current
      const elapsed = now - state.startedAt
      const progress = Math.min(1, elapsed / Math.max(state.durationMs, 1))
      const scrub = state.startScrub + (state.endScrub - state.startScrub) * progress
      setScrubTime(scrub)
      setTourChapterIndex(state.chapterIndex)

      if (progress >= 1) {
        const nextIndex = state.chapterIndex + 1
        if (nextIndex >= chapters.length) {
          stopChapterTour()
          return
        }
        const durations = chapterTourDurations(chapters, CHAPTER_TOUR_MS)
        const startScrub = chapterStartScrub(chapters[nextIndex], chartTiming.tMin, chartTiming.tRange) ?? 0
        const endScrub = chapterEndScrub(chapters[nextIndex], chartTiming.tMin, chartTiming.tRange) ?? startScrub
        tourRef.current = {
          chapterIndex: nextIndex,
          startedAt: now,
          durationMs: durations[nextIndex] ?? CHAPTER_TOUR_MS / chapters.length,
          startScrub,
          endScrub,
        }
      }
      frame = requestAnimationFrame(tick)
    }

    frame = requestAnimationFrame(tick)
    return () => cancelAnimationFrame(frame)
  }, [chapterTourActive, chartTiming, chapters])

  useEffect(() => {
    if (!chapterTourActive) return
    const onKeyDown = (event: KeyboardEvent) => {
      if (event.key === 'Escape') {
        stopChapterTour()
      }
    }
    window.addEventListener('keydown', onKeyDown)
    return () => window.removeEventListener('keydown', onKeyDown)
  }, [chapterTourActive])

  const replayTMs = useMemo(() => {
    const replay = replayQuery.data
    const frames = replay?.frames ?? []
    if (frames.length === 0) return 0
    const lastFrameT = frames[frames.length - 1].t
    const progress = scrubTime ?? 0
    if (!chartTiming || !replay?.start_time) {
      return Math.max(0, Math.min(lastFrameT, Math.round(progress * lastFrameT)))
    }
    const replayStart = new Date(replay.start_time).getTime()
    const chartTime = chartTiming.tMin + progress * chartTiming.tRange
    return Math.max(0, Math.min(lastFrameT, Math.round(chartTime - replayStart)))
  }, [chartTiming, replayQuery.data, scrubTime])

  let chartContent = null
  let displayResults = results

  if (hasChartData && chartTiming) {
    const { tMin, tRange } = chartTiming
    const normaliseTime = (time: number) => Math.max(0, Math.min(1, (time - tMin) / tRange))

    const byDriver = new Map<number, Array<{ t: number; pos: number }>>()
    for (const p of positions) {
      const time = new Date(p.date).getTime()
      if (!Number.isFinite(time)) continue
      if (!byDriver.has(p.driver_number)) byDriver.set(p.driver_number, [])
      byDriver.get(p.driver_number)!.push({
        t: normaliseTime(time),
        pos: p.position,
      })
    }
    const dnfSet = new Set(results.filter((r) => r.dnf || r.dns || r.dsq).map((r) => r.driver_number))
    for (const [dNum, samples] of byDriver.entries()) {
      samples.sort((a, b) => a.t - b.t)
      if (samples.length > 0 && !dnfSet.has(dNum)) {
        samples.push({ t: 1, pos: samples[samples.length - 1].pos })
      }
    }

    const getInterpPos = (samples: { t: number; pos: number }[], t: number) => {
      if (!samples || samples.length === 0) return null
      if (t <= samples[0].t) return samples[0].pos
      if (t >= samples[samples.length - 1].t) return samples[samples.length - 1].pos
      for (let i = 0; i < samples.length - 1; i++) {
        if (samples[i].t <= t && samples[i + 1].t >= t) {
          const dt = samples[i + 1].t - samples[i].t
          if (dt === 0) return samples[i].pos
          const frac = (t - samples[i].t) / dt
          return samples[i].pos + (samples[i + 1].pos - samples[i].pos) * frac
        }
      }
      return null
    }

    if (scrubTime !== null) {
      const currentPos = new Map<number, number>()
      for (const [dNum, samples] of byDriver.entries()) {
        const pos = getInterpPos(samples, scrubTime)
        if (pos !== null) {
          currentPos.set(dNum, pos)
        }
      }
      displayResults = [...results].sort((a, b) => {
        const posA = currentPos.get(a.driver_number) ?? 999
        const posB = currentPos.get(b.driver_number) ?? 999
        return posA - posB
      })
    }

    const maxPos = Math.max(...positions.map((p) => p.position), results.length, 2)
    const colorByDriver = new Map(results.map((r) => [r.driver_number, r.team_colour]))
    const acronymByDriver = new Map(results.map((r) => [r.driver_number, r.name_acronym]))
    const positionLabels = decimatedPositionLabels(maxPos)

    const W = CHART_W
    const H = CHART_H
    const PL = CHART_PL
    const PR = CHART_PR
    const PT = CHART_PT
    const PB = CHART_PB
    const plotW = W - PL - PR
    const plotH = H - PT - PB

    const toX = (t: number) => PL + t * plotW
    const toY = (pos: number) => PT + ((pos - 1) / Math.max(maxPos - 1, 1)) * plotH

    const winner = results.find((r) => r.position === 1)
    const winnerLaps = winner ? laps.filter((l) => l.driver_number === winner.driver_number) : []
    const lapTicks: { lap: number; t: number }[] = []
    const lapInterval = winnerLaps.length < 30 ? 5 : 10

    for (let i = 0; i < winnerLaps.length; i++) {
      const lap = winnerLaps[i]
      if (lap.lap_number > 0 && lap.lap_number % lapInterval === 0) {
        const lapStart = new Date(lap.date_start).getTime()
        const nextLapStart = winnerLaps[i + 1] ? new Date(winnerLaps[i + 1].date_start).getTime() : NaN
        const lapEnd = lap.lap_duration && lap.lap_duration > 0
          ? lapStart + lap.lap_duration * 1000
          : nextLapStart
        if (Number.isFinite(lapEnd)) lapTicks.push({ lap: lap.lap_number, t: normaliseTime(lapEnd) })
      }
    }

    const scPeriods: { start: number; end: number | null; type: 'SC' | 'VSC' }[] = []
    let activeSC: { start: number; type: 'SC' | 'VSC' } | null = null
    const rc = [...race_control].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime())

    for (const msg of rc) {
      const t = new Date(msg.date).getTime()
      const m = msg.message?.toUpperCase() || ''
      const cat = msg.category?.toUpperCase() || ''

      if (m.includes('VIRTUAL SAFETY CAR DEPLOYED') || cat === 'VIRTUALSAFETYCAR') {
        if (!activeSC) activeSC = { start: t, type: 'VSC' }
      } else if (m.includes('SAFETY CAR DEPLOYED') || cat === 'SAFETYCAR') {
        if (!activeSC) activeSC = { start: t, type: 'SC' }
      } else if (m.includes('TRACK CLEAR') || m.includes('CLEAR')) {
        if (activeSC) {
          scPeriods.push({ start: activeSC.start, end: t, type: activeSC.type })
          activeSC = null
        }
      }
    }
    if (activeSC) {
      scPeriods.push({ start: activeSC.start, end: null, type: activeSC.type })
    }

    const chapterBands = chapters
      .map((chapter, index) => {
        const startT = chapterStartScrub(chapter, tMin, tRange)
        const endT = chapterEndScrub(chapter, tMin, tRange)
        if (startT === null) return null
        const end = endT ?? startT
        return {
          key: `${chapter.kind}-${index}`,
          start: Math.min(startT, end),
          end: Math.max(startT, end),
          fill: chapterBandFill(chapter.kind),
        }
      })
      .filter((band): band is NonNullable<typeof band> => band !== null)

    const labelCandidates = Array.from(byDriver.entries())
      .map(([dNum, samples]) => {
        const last = samples[samples.length - 1]
        if (!last) return null
        return { key: dNum, y: toY(last.pos) }
      })
      .filter((item): item is { key: number; y: number } => item !== null)
    const labelYByDriver = deCollideYPositions(labelCandidates, 12)

    const handlePointerMove = (e: React.PointerEvent<SVGRectElement>) => {
      setIsPlaying(false)
      stopChapterTour()
      clearChapterSelection()
      if (!svgRef.current) return
      const rect = svgRef.current.getBoundingClientRect()
      if (rect.width <= 0) return
      // Pointer coordinates are CSS pixels; convert them to the SVG viewBox
      // before comparing with the fixed chart margins and plot width.
      const x = ((e.clientX - rect.left) / rect.width) * W
      const t = Math.max(0, Math.min(1, (x - PL) / plotW))
      setScrubTime(t)
    }

    chartContent = (
      <div
        className={`rs-chart-container scroll-x${showMapPanel ? '' : ' rs-chart-container--full'}`}
        data-testid="position-chart"
      >
        <svg
          ref={svgRef}
          className="rs-position-chart-svg"
          viewBox={`0 0 ${W} ${H}`}
          role="img"
          aria-label="Position evolution chart"
        >
          {chapterBands.map((band) => {
            const x1 = toX(Math.max(0, band.start))
            const x2 = toX(Math.min(1, band.end))
            if (x2 <= PL || x1 >= W - PR) return null
            return (
              <rect
                key={band.key}
                x={x1}
                y={PT}
                width={Math.max(0, x2 - x1)}
                height={plotH}
                fill={band.fill}
                data-testid="chapter-band"
              />
            )
          })}

          {scPeriods.map((sc, i) => {
            const startT = (sc.start - tMin) / tRange
            const endT = sc.end ? (sc.end - tMin) / tRange : 1
            const x1 = toX(Math.max(0, startT))
            const x2 = toX(Math.min(1, endT))
            if (x2 <= PL || x1 >= W - PR) return null
            return (
              <rect
                key={`sc-${i}`}
                x={x1}
                y={PT}
                width={Math.max(0, x2 - x1)}
                height={plotH}
                fill={sc.type === 'SC' ? 'rgba(255, 153, 0, 0.15)' : 'rgba(255, 204, 0, 0.1)'}
              />
            )
          })}

          {positionLabels.map((pos) => (
            <g key={pos}>
              <line
                x1={PL}
                x2={W - PR}
                y1={toY(pos)}
                y2={toY(pos)}
                className="rs-chart-grid-line"
              />
              <text
                x={PL - 4}
                y={toY(pos) + 4}
                textAnchor="end"
                className="rs-chart-axis-label"
              >
                P{pos}
              </text>
            </g>
          ))}

          {lapTicks.map((tick) => (
            <g key={`lap-${tick.lap}`}>
              <line
                x1={toX(tick.t)}
                x2={toX(tick.t)}
                y1={H - PB}
                y2={H - PB + 4}
                className="rs-chart-lap-tick"
              />
              <text
                x={toX(tick.t)}
                y={H - PB + 14}
                textAnchor="middle"
                className="rs-chart-axis-label"
              >
                L{tick.lap}
              </text>
            </g>
          ))}

          {Array.from(byDriver.entries()).map(([dNum, samples]) => {
            const colour = colorByDriver.get(dNum)
            const color = colour ? `#${colour}` : '#888'
            const pts = samples.map((s) => `${toX(s.t)},${toY(s.pos)}`).join(' ')
            const last = samples[samples.length - 1]
            const isHovered = hoverDriver === dNum
            const isFaded = hoverDriver !== null && !isHovered
            const labelY = last ? (labelYByDriver.get(dNum) ?? toY(last.pos)) : 0

            const driverPits = pit_stops.filter((p) => p.driver_number === dNum)

            return (
              <g
                key={dNum}
                style={{ opacity: isFaded ? 0.2 : 1, transition: 'opacity 0.2s' }}
                onMouseEnter={() => setHoverDriver(dNum)}
                onMouseLeave={() => setHoverDriver(null)}
              >
                <polyline
                  points={pts}
                  fill="none"
                  stroke={color}
                  strokeWidth={isHovered ? 3 : 2}
                  strokeLinejoin="round"
                  strokeLinecap="round"
                  className="rs-driver-line"
                  pathLength={1}
                />

                {driverPits.map((p, i) => {
                  const time = new Date(p.date).getTime()
                  if (!Number.isFinite(time) || time < tMin || time > tMin + tRange) return null
                  const t = normaliseTime(time)
                  const pos = getInterpPos(samples, t)
                  if (pos === null) return null
                  return (
                    <circle
                      key={`pit-${i}`}
                      cx={toX(t)}
                      cy={toY(pos)}
                      r={3}
                      fill="var(--bg)"
                      stroke={color}
                      strokeWidth={2}
                      className="rs-pit-dot"
                    />
                  )
                })}

                {last && (
                  <text
                    x={toX(last.t) + 6}
                    y={labelY + 4}
                    fill={color}
                    fontSize={isHovered ? 11 : 9}
                    fontFamily="var(--f-mono)"
                    fontWeight={700}
                    style={{ cursor: 'default' }}
                  >
                    {acronymByDriver.get(dNum) ?? dNum}
                  </text>
                )}
              </g>
            )
          })}

          {scrubTime !== null && (
            <line
              x1={toX(scrubTime)}
              x2={toX(scrubTime)}
              y1={PT}
              y2={H - PB}
              stroke="var(--text)"
              strokeWidth={1}
              strokeDasharray="4 2"
              className="rs-playhead"
              style={{ pointerEvents: 'none' }}
            />
          )}

          <rect
            x={PL}
            y={PT}
            width={plotW}
            height={plotH}
            fill="transparent"
            data-testid="position-chart-interaction"
            onPointerMove={handlePointerMove}
            onPointerLeave={() => {
              if (!isPlaying) {
                clearChapterSelection()
                setScrubTime(null)
              }
            }}
            style={{ cursor: 'crosshair', touchAction: 'none' }}
          />
        </svg>
        <div className="rs-segmented-control" aria-label="Race replay controls" data-testid="replay-controls">
          <button
            type="button"
            className={`rs-segment ${isPlaying ? 'active' : ''}`}
            onClick={() => {
              setScrubTime((current) => current ?? 0)
              stopChapterTour()
              clearChapterSelection()
              setIsPlaying((current) => !current)
            }}
            aria-pressed={isPlaying}
          >
            {isPlaying ? 'Pause' : 'Play'}
          </button>
          <span className="rs-segment-divider" aria-hidden />
          {[1, 10, 30].map((speed) => (
            <button
              key={speed}
              type="button"
              className={`rs-segment ${playbackSpeed === speed ? 'active' : ''}`}
              onClick={() => setPlaybackSpeed(speed)}
              aria-pressed={playbackSpeed === speed}
            >
              {speed}x
            </button>
          ))}
          {mapProbeSettled && mapAvailable && (
            <>
              <span className="rs-segment-divider" aria-hidden />
              <button
                type="button"
                className={`rs-segment ${mapOpen ? 'active' : ''}`}
                onClick={() => setMapOpen((current) => !current)}
                aria-pressed={mapOpen}
                data-testid="replay-map-toggle"
              >
                Map
              </button>
            </>
          )}
        </div>
      </div>
    )
  }

  return (
    <div className="race-story-canvas">
      {hasChartData && chartTiming && chapters.length > 0 && (
        <ChapterStrip
          chapters={chapters}
          scrubTime={scrubTime}
          tMin={chartTiming.tMin}
          tRange={chartTiming.tRange}
          tourActive={chapterTourActive}
          tourChapterIndex={tourChapterIndex}
          selectedChapterIndex={selectedChapterIndex}
          onChapterClick={jumpToChapter}
          onTourToggle={toggleChapterTour}
        />
      )}
      <div className={`rs-replay-shell${showMapPanel ? ' rs-replay-shell--split' : ''}`}>
        <div className="rs-replay-main">
          {hasChartData ? (
            chartContent
          ) : (
            <EmptyStateCard
              icon={LineChart}
              title="Lap-by-lap positions not available"
              hint={
                <>
                  This session does not have ingested position samples in{' '}
                  <code>/api/v1/race-hub</code>.
                </>
              }
              testId="race-story-no-positions"
              className="race-story-empty-card"
            />
          )}
        </div>
        {showMapPanel && (
          <div className="rs-replay-map-slot" data-testid="replay-map-slot">
            <ReplayTrackMap
              outline={outlineQuery.data}
              replay={replayQuery.data}
              tMs={replayTMs}
              drivers={drivers}
              results={results}
              loading={outlineQuery.isLoading || replayQuery.isLoading}
              error={outlineQuery.isError || replayQuery.isError}
            />
          </div>
        )}
      </div>

      {displayResults.length > 0 && (
        <div className="rs-field-list">
          {displayResults.map((r, i) => {
            const gridPos = grid.find((g) => g.driver_number === r.driver_number)?.position ?? 0
            const currentPos = scrubTime !== null ? i + 1 : r.position
            const isWinner = i === 0 && r.position === 1
            const pClass =
              currentPos === 1 ? 'rs-pos-p1' : currentPos === 2 ? 'rs-pos-p2' : currentPos === 3 ? 'rs-pos-p3' : ''

            let currentPoints: number | string = r.points
            if (scrubTime !== null) {
              const isSprint = data.session?.session_type?.toLowerCase().includes('sprint')
              const ptsArray = isSprint ? [8, 7, 6, 5, 4, 3, 2, 1] : [25, 18, 15, 12, 10, 8, 6, 4, 2, 1]
              currentPoints = currentPos <= ptsArray.length ? ptsArray[currentPos - 1] : 0
            }

            return (
              <div
                key={r.driver_number}
                className={`rs-driver-row ${hoverDriver === r.driver_number ? 'rs-driver-row-hover' : ''}`}
                onMouseEnter={() => setHoverDriver(r.driver_number)}
                onMouseLeave={() => setHoverDriver(null)}
              >
                <div className="rs-driver-left">
                  <div className={`rs-pos-col ${pClass}`}>{currentPos}</div>
                  <div className="rs-driver-cell">
                    <div
                      className="rs-driver-color"
                      style={{ background: r.team_colour ? `#${r.team_colour}` : 'var(--border)' }}
                    />
                    <div className="rs-driver-identity">
                      <span className="rs-driver-name">{r.name_acronym || r.driver_number}</span>
                      <span className="rs-driver-team">{r.team_name}</span>
                    </div>
                  </div>
                </div>

                <div className="rs-driver-right">
                  <div className="rs-metric">
                    <span>
                      <span className={gridDeltaClass(currentPos, gridPos)}>
                        {gridDelta(currentPos, gridPos)}
                      </span>
                    </span>
                    <span className="rs-metric-label">Grid</span>
                  </div>

                  <div className="rs-metric" style={{ width: '80px', opacity: scrubTime !== null ? 0.3 : 1 }}>
                    <span>{isWinner ? formatDuration(r.duration) : formatGap(r.gap_to_leader)}</span>
                    <span className="rs-metric-label">{isWinner ? 'Time' : 'Gap'}</span>
                  </div>

                  <div className="rs-metric" style={{ width: '40px' }}>
                    <span style={{ color: Number(currentPoints) > 0 ? 'var(--text)' : 'var(--text-3)' }}>
                      {currentPoints}
                    </span>
                    <span className="rs-metric-label">Pts</span>
                  </div>
                </div>
              </div>
            )
          })}
        </div>
      )}
    </div>
  )
}
