import { describe, expect, it } from 'vitest';

import fixMasterAmplitude from './fixMasterAmplitude';
import fixMetronome from './fixMetronome';
import fixProjectLoop from './fixProjectLoop';
import { fixSongFadeInBeats, fixSongFadeOutBeats } from './fixSongFades';

describe('fixMasterAmplitude', () => {
  it('should return 1.0 for non-numbers', () => {
    expect(fixMasterAmplitude(null)).toBe(1.0);
    expect(fixMasterAmplitude(undefined)).toBe(1.0);
    expect(fixMasterAmplitude('string')).toBe(1.0);
    expect(fixMasterAmplitude(NaN)).toBe(1.0);
    expect(fixMasterAmplitude(Infinity)).toBe(1.0);
  });

  it('should return valid amplitudes unchanged', () => {
    expect(fixMasterAmplitude(0.5)).toBe(0.5);
    expect(fixMasterAmplitude(1.0)).toBe(1.0);
    expect(fixMasterAmplitude(2.0)).toBe(2.0);
  });

  it('should reject negative amplitudes', () => {
    expect(fixMasterAmplitude(-1.0)).toBe(1.0);
  });
});

describe('fixSongFades', () => {
  it('should default to 0 for invalid values', () => {
    expect(fixSongFadeInBeats(null)).toBe(0);
    expect(fixSongFadeOutBeats(undefined)).toBe(0);
    expect(fixSongFadeInBeats(NaN)).toBe(0);
    expect(fixSongFadeOutBeats(Infinity)).toBe(0);
  });

  it('should return valid fade values unchanged', () => {
    expect(fixSongFadeInBeats(2.5)).toBe(2.5);
    expect(fixSongFadeOutBeats(4.0)).toBe(4.0);
  });

  it('should reject negative fades', () => {
    expect(fixSongFadeInBeats(-1.0)).toBe(0);
    expect(fixSongFadeOutBeats(-2.0)).toBe(0);
  });
});

describe('fixMetronome', () => {
  it('should return defaults for null/undefined', () => {
    const result = fixMetronome(null);
    expect(result.enabled).toBe(false);
    expect(result.amplitude).toBe(1.0);
  });

  it('should fix metronome in place', () => {
    const input = {
      enabled: true,
      amplitude: 0.8,
    };

    const result = fixMetronome(input);

    expect(result).toBe(input); // Referential equality
    expect(result.enabled).toBe(true);
    expect(result.amplitude).toBe(0.8);
  });

  it('should fix invalid fields', () => {
    const input = {
      enabled: 'not a boolean',
      amplitude: NaN,
    };

    const result = fixMetronome(input);

    expect(result.enabled).toBe(false);
    expect(result.amplitude).toBe(1.0);
  });

  it('should reject negative amplitude', () => {
    const result = fixMetronome({ amplitude: -1.0 });
    expect(result.amplitude).toBe(1.0);
  });
});

describe('fixProjectLoop', () => {
  it('should return defaults for null/undefined', () => {
    const result = fixProjectLoop(null);
    expect(result.enabled).toBe(false);
    expect(result.startBeats).toBe(0);
    expect(result.endBeats).toBe(32);
  });

  it('should fix loop in place', () => {
    const input = {
      enabled: true,
      startBeats: 4,
      endBeats: 20,
    };

    const result = fixProjectLoop(input);

    expect(result).toBe(input); // Referential equality
    expect(result.enabled).toBe(true);
    expect(result.startBeats).toBe(4);
    expect(result.endBeats).toBe(20);
  });

  it('should allow negative beats', () => {
    const result = fixProjectLoop({
      enabled: true,
      startBeats: -4,
      endBeats: 8,
    });

    expect(result.startBeats).toBe(-4);
    expect(result.endBeats).toBe(8);
  });

  it('should ensure endBeats > startBeats', () => {
    const result1 = fixProjectLoop({
      startBeats: 10,
      endBeats: 10,
    });
    expect(result1.endBeats).toBe(42); // 10 + 32

    const result2 = fixProjectLoop({
      startBeats: 10,
      endBeats: 5,
    });
    expect(result2.endBeats).toBe(42); // 10 + 32
  });
});
