'use babel';

// Lightweight role ontology for ParVagues orbits. Five buckets keyed off
// (1) sample-name content, (2) group-routing hints, (3) orbit-number
// convention. Role drives the HUD color palette — at-a-glance scannability
// trumps unique-per-orbit identity.

export const ROLE_RHYTHM = 'rhythm';
export const ROLE_BASS   = 'bass';
export const ROLE_LEAD   = 'lead';
export const ROLE_PAD    = 'pad';
export const ROLE_RISER  = 'riser';

// Pattern order matters: more specific keywords first, generic catch-alls
// last. `riser` before `rhythm` so "risers:N" doesn't get eaten by the
// drum-y wordlist; `rhythm` before `bass` so "808bd" stays a kick.
const PATTERNS = [
  { role: ROLE_RISER,  re: /\b(risers?|sweep|whoosh|uplifter|fx_uplift)/i },
  { role: ROLE_RHYTHM, re: /\b(kick|^bd|:bd|808bd|808bb|sn|snare|hh|oh|ch|hat|breaks?|drums?|dr[:_]|808|clap|cymbal|tom|perc|rim|cowbell|casio:0|electro|jungle_breaks|gretsch|vec\d+_snare|cp[:_])/i },
  { role: ROLE_BASS,   re: /\b(bass|sub|cbow|cpluck|moogbass|basswarsaw|bassdm|acid|cb[:_]|bassdrum)/i },
  { role: ROLE_PAD,    re: /\b(pad|voice|vox|choir|noise|wind|rain|ambient|drone|ghost|foul|suns|birds|crow|atmosph|air)/i },
  { role: ROLE_LEAD,   re: /\b(lead|synth_|gameboy|arpy|piano|keys|nujazz_keys|nujazz_guitar|fpiano|qstab|pluck|melody|guitar)/i }
];

// Per-orbit fallback when sound is unknown or doesn't match any pattern.
// Mirrors ParVagues channel convention: low orbits = rhythm/bass, mids =
// melodic, highs = atmospheric.
const DEFAULT_BY_ORBIT = {
  1:  ROLE_RHYTHM,
  2:  ROLE_RHYTHM,
  3:  ROLE_RHYTHM,
  4:  ROLE_BASS,
  5:  ROLE_LEAD,
  6:  ROLE_RHYTHM,
  7:  ROLE_RHYTHM,
  8:  ROLE_RHYTHM,
  9:  ROLE_PAD,
  10: ROLE_RISER,
  11: ROLE_LEAD,
  12: ROLE_LEAD
};

// Returns { role, source, matched } so the HUD tooltip can show *why*.
//   source: 'sound' | 'group' | 'orbit-default' | 'none'
//   matched: the substring that triggered the match (for sound source)
export function classifyRole(orbit) {
  if (orbit && orbit.sound) {
    const s = String(orbit.sound).toLowerCase();
    for (const { role, re } of PATTERNS) {
      const m = s.match(re);
      if (m) return { role, source: 'sound', matched: m[0] };
    }
  }
  // gF2 = djfbus 2 in ParVagues convention = bass channel routing.
  if (orbit && orbit.uses && orbit.uses.includes('gF2')) {
    return { role: ROLE_BASS, source: 'group', matched: 'gF2' };
  }
  if (orbit && DEFAULT_BY_ORBIT[orbit.n]) {
    return { role: DEFAULT_BY_ORBIT[orbit.n], source: 'orbit-default', matched: `d${orbit.n}` };
  }
  return { role: null, source: 'none', matched: null };
}
