/**
 * @vitest-environment happy-dom
 */
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import {
  HapticEngine,
  loadSoundEnabled,
  loadSoundVolume,
  SFX_STORAGE_KEY,
  SFX_VOLUME_KEY,
} from './hapticEngine';

describe('hapticEngine prefs', () => {
  beforeEach(() => {
    localStorage.clear();
  });

  it('defaults sound on and volume ~0.4', () => {
    expect(loadSoundEnabled()).toBe(true);
    expect(loadSoundVolume()).toBeCloseTo(0.4);
  });

  it('persists enabled flag', () => {
    const e = new HapticEngine();
    e.setEnabled(false);
    expect(localStorage.getItem(SFX_STORAGE_KEY)).toBe('0');
    expect(loadSoundEnabled()).toBe(false);
  });

  it('clamps volume', () => {
    const e = new HapticEngine();
    e.setVolume(2);
    expect(e.getVolume()).toBe(1);
    e.setVolume(-1);
    expect(e.getVolume()).toBe(0);
    expect(localStorage.getItem(SFX_VOLUME_KEY)).toBe('0');
  });
});

describe('HapticEngine.play', () => {
  const vibrate = vi.fn();

  beforeEach(() => {
    vibrate.mockClear();
    Object.defineProperty(navigator, 'vibrate', {
      value: vibrate,
      configurable: true,
      writable: true,
    });
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('does not vibrate when disabled', () => {
    const e = new HapticEngine();
    e.setEnabled(false);
    e.play('click');
    expect(vibrate).not.toHaveBeenCalled();
  });

  it('vibrates when enabled', () => {
    const e = new HapticEngine();
    e.setEnabled(true);
    e.play('success');
    expect(vibrate).toHaveBeenCalled();
  });

  it('play does not throw without AudioContext', () => {
    const prev = globalThis.AudioContext;
    // @ts-expect-error test shim
    delete globalThis.AudioContext;
    const e = new HapticEngine();
    e.setEnabled(true);
    expect(() => e.play('click')).not.toThrow();
    globalThis.AudioContext = prev;
  });
});
