import type { SwitchType } from '../types';

export type SoundPhase = 'press' | 'release';
export type PressSampleKey =
  | 'SPACE'
  | 'ENTER'
  | 'BACKSPACE'
  | 'GENERIC_R0'
  | 'GENERIC_R1'
  | 'GENERIC_R2'
  | 'GENERIC_R3'
  | 'GENERIC_R4';
export type ReleaseSampleKey = 'SPACE' | 'ENTER' | 'BACKSPACE' | 'GENERIC';

export type SwitchManifest = {
  press: string[];
  release: string[];
};

export const DEFAULT_RELEASE_OFFSET = 0.08;

const SPECIAL_KEY_SAMPLES: Record<string, PressSampleKey> = {
  Space: 'SPACE',
  Enter: 'ENTER',
  Backspace: 'BACKSPACE',
};

/** djb2 hash for stable per-key press variant selection. */
export function hashCode(value: string): number {
  let hash = 5381;
  for (let i = 0; i < value.length; i++) {
    hash = (hash * 33) ^ value.charCodeAt(i);
  }
  return hash >>> 0;
}

export function pressVariantIndex(code: string): number {
  return hashCode(code) % 5;
}

export function pressVariantKey(code: string): PressSampleKey {
  return `GENERIC_R${pressVariantIndex(code)}` as PressSampleKey;
}

/** Pick a press sample key from special-key map or GENERIC_R0–R4 variant. */
export function resolvePressSampleKey(
  keyLabel: string,
  code: string,
  available: string[],
): PressSampleKey {
  const special = SPECIAL_KEY_SAMPLES[keyLabel];
  if (special && available.includes(special)) return special;
  const variant = pressVariantKey(code);
  if (available.includes(variant)) return variant;
  const fallback = `GENERIC_R${pressVariantIndex(code)}`;
  if (available.includes(fallback)) return fallback as PressSampleKey;
  const generic = available.find((s) => s.startsWith('GENERIC_R'));
  return (generic ?? available[0]) as PressSampleKey;
}

/** Pick a release sample key, preferring special keys then GENERIC. */
export function resolveReleaseSampleKey(
  keyLabel: string,
  available: string[],
): ReleaseSampleKey {
  const special = SPECIAL_KEY_SAMPLES[keyLabel];
  if (special && available.includes(special)) return special as ReleaseSampleKey;
  if (available.includes('GENERIC')) return 'GENERIC';
  return (available[0] ?? 'GENERIC') as ReleaseSampleKey;
}

export function sampleUrl(
  switchType: SwitchType,
  phase: SoundPhase,
  sampleKey: string,
): string {
  return `/assets/samples/kbsim/${switchType}/${phase}/${sampleKey}.mp3`;
}

/** Keyup timestamp; defaults to press time + 80 ms when not recorded. */
export function markerReleaseTime(marker: {
  time: number;
  releaseTime?: number;
}): number {
  return marker.releaseTime ?? marker.time + DEFAULT_RELEASE_OFFSET;
}
