import { describe, expect, it } from 'vitest';
import {
  MOOD_GROUP_IDS,
  MOOD_GROUPS,
  OXIMEDIA_MOOD_TAG_IDS,
  TOP_OXIMEDIA_MOOD_TAG_TEST_SCORES,
  moodScoresFromValenceArousal,
  topDistinctOximediaMoodTagIds,
  topDistinctOximediaMoodTagIdsFromValenceArousal,
  topOximediaMoodTagIds,
} from './moodGroups';

/** Keep in sync with `psysonic_library::mood_groups` invariant tests. */
describe('moodGroups catalog invariants', () => {
  it('group ids match Rust MOOD_GROUP_IDS', () => {
    expect([...MOOD_GROUP_IDS]).toEqual(['joy', 'sadness', 'dance', 'work', 'romance', 'anger']);
  });

  it('every oximedia tag appears in at least one group', () => {
    for (const tag of OXIMEDIA_MOOD_TAG_IDS) {
      expect(MOOD_GROUPS.some(g => g.tags.includes(tag))).toBe(true);
    }
  });

  it('joy group tags match Rust expand_mood_groups', () => {
    expect(MOOD_GROUPS.find(g => g.id === 'joy')?.tags).toEqual(['happy', 'excited']);
  });

  it('work and romance groups overlap on calm/peaceful', () => {
    const work = MOOD_GROUPS.find(g => g.id === 'work')!.tags;
    const romance = MOOD_GROUPS.find(g => g.id === 'romance')!.tags;
    expect(work.some(t => romance.includes(t))).toBe(true);
  });

  it('anger group tags match Rust expand_mood_groups', () => {
    expect(MOOD_GROUPS.find(g => g.id === 'anger')?.tags).toEqual(['angry', 'tense']);
  });
});

describe('moodScoresFromValenceArousal', () => {
  it('never shows both happy and excited for typical oximedia pop', () => {
    const labels = topDistinctOximediaMoodTagIdsFromValenceArousal(0.4, 0.75);
    expect(labels.includes('happy') && labels.includes('excited')).toBe(false);
    expect(labels.length).toBeLessThanOrEqual(2);
  });

  it('prefers calm or peaceful for low arousal', () => {
    const labels = topDistinctOximediaMoodTagIdsFromValenceArousal(0.55, 0.42);
    expect(labels.some(id => id === 'calm' || id === 'peaceful')).toBe(true);
  });
});

describe('topOximediaMoodTagIds', () => {
  it('matches Rust top_oximedia_mood_tag_ids_from_moods_json test vector', () => {
    expect(topOximediaMoodTagIds(TOP_OXIMEDIA_MOOD_TAG_TEST_SCORES)).toEqual([
      'happy',
      'excited',
      'calm',
    ]);
  });

  it('sorts by score descending with id tie-break', () => {
    expect(topOximediaMoodTagIds({ calm: 0.2, happy: 0.9, excited: 0.5 })).toEqual([
      'happy',
      'excited',
      'calm',
    ]);
  });
});
