import { useMemo } from 'react'
import type { OrbitActivity, RoleGroup } from '@/types'

interface Props {
  /** seconds per activity bin */
  binS: number
  orbits: OrbitActivity[]
  roleGroups: RoleGroup[]
  currentTime: number
  /** "strongly on / driving" — full intensity at/above this dB */
  activeDb: number
  /** audible floor — orbit is shown (dim) above this, hidden below it */
  litFloorDb: number
}

/**
 * The orbit-group rail: five labelled lanes (role families), showing the orbits
 * active in THIS take, lit by their RMS at the playhead. Labels + families are
 * derived from the track's score + measured spectrum (build_player_data, #40).
 *
 * Activation is GRADED, not a hard on/off: a sound clearly audible can dip below
 * the old −38 dB gate within a 2 s bin and would wrongly go dark (PLN saw only
 * d3 OR d8 while hearing both). Now an orbit shows above `litFloorDb` (~−52) and
 * its intensity ramps to full by `activeDb`, so a quiet-but-playing orbit never
 * vanishes — it just dims.
 *
 * Takes `binS` + `orbits` rather than a whole Take so the set-judge (a LIST of
 * tracks, not an A/B of two takes) reuses the same rail. One rail, one meaning.
 */
export function OrbitRail({ binS, orbits: all, roleGroups, currentTime, activeDb, litFloorDb }: Props) {
  const bin = Math.max(0, Math.floor(currentTime / binS))
  const byGroup = useMemo(() => {
    const m: Record<string, OrbitActivity[]> = {}
    for (const o of all) (m[o.group] ??= []).push(o)
    return m
  }, [all])

  // dB → 0..1: 0 at the audible floor, 1 by the "driving" threshold.
  const intensity = (db: number) => {
    if (!isFinite(db) || db <= litFloorDb) return 0
    return Math.max(0, Math.min(1, (db - litFloorDb) / (activeDb - litFloorDb)))
  }

  return (
    <div className="flex flex-col gap-px overflow-hidden rounded-md border border-hairline">
      {roleGroups.map((g) => {
        const orbits = byGroup[g.key] ?? []
        const laneLit = orbits.some((o) => (o.activity[bin] ?? -240) > litFloorDb)
        return (
          <div key={g.key} className="flex items-stretch gap-2 bg-raised px-2 py-1.5">
            <div
              className="flex w-20 shrink-0 items-center gap-1.5 text-xs font-medium transition-colors"
              style={{ color: laneLit ? g.color : 'var(--color-ink-faint)' }}
            >
              <span aria-hidden className="text-sm leading-none">{g.glyph}</span>
              <span>{g.label}</span>
            </div>
            <div className="flex min-w-0 flex-wrap items-center gap-1.5">
              {orbits.length === 0 && (
                <span className="text-xs text-ink-faint/60">—</span>
              )}
              {orbits.map((o) => {
                const db = o.activity[bin] ?? -240
                const lvl = intensity(db) // 0..1
                const lit = lvl > 0
                // dim-but-visible at the floor, vivid when driving (0.35 → 1.0)
                const op = lit ? 0.35 + 0.65 * lvl : 1
                const cenTip = o.centroid ? ` · ${o.centroid}Hz` : ''
                return (
                  <span
                    key={o.orbit}
                    title={`orbit-${o.orbit} · ${o.label} · ${o.group}${cenTip} · ${
                      isFinite(db) ? db.toFixed(0) : '−∞'
                    } dB`}
                    className="relative flex items-center gap-1 overflow-hidden rounded-full
                               border px-2 py-0.5 font-mono text-[11px] tnum transition-all"
                    style={{
                      borderColor: lit ? g.color : 'var(--color-hairline)',
                      color: lit ? g.color : 'var(--color-ink-faint)',
                      background: lit ? `${g.color}1a` : 'transparent',
                      opacity: op,
                    }}
                  >
                    {/* level fill — reinforces loudness without relying on hue alone */}
                    {lit && (
                      <span
                        aria-hidden
                        className="absolute inset-y-0 left-0"
                        style={{ width: `${lvl * 100}%`, background: `${g.color}22` }}
                      />
                    )}
                    <span className="relative">{o.label}</span>
                    <span className="relative opacity-60">·{o.orbit}</span>
                  </span>
                )
              })}
            </div>
          </div>
        )
      })}
    </div>
  )
}
