import { afterEach, describe, expect, it, vi } from 'vitest';
import { setAlphabet } from '../alphabet';

// getDawg is the only side-effecting dependency; stub it so the test exercises localWordCheck's
// own logic (load -> encode -> membership -> null handling) against a fake reader, not a real DAWG.
vi.mock('./loader', () => ({ getDawg: vi.fn() }));
import { getDawg } from './loader';
import { localWordCheck } from './check';

const mockedGetDawg = vi.mocked(getDawg);

// A tiny cached alphabet so indexForLetter can encode the test words.
setAlphabet('scrabble_en', [
  { index: 0, letter: 'A', value: 1 },
  { index: 1, letter: 'B', value: 3 },
  { index: 2, letter: 'C', value: 3 },
]);

describe('localWordCheck', () => {
  afterEach(() => vi.clearAllMocks());

  it('returns true when the dawg contains the word', async () => {
    mockedGetDawg.mockResolvedValue({ indexOf: () => 5 } as never);
    expect(await localWordCheck('scrabble_en', 'v1', 'AB')).toBe(true);
  });

  it('returns false when the dawg does not contain the word', async () => {
    mockedGetDawg.mockResolvedValue({ indexOf: () => -1 } as never);
    expect(await localWordCheck('scrabble_en', 'v1', 'AB')).toBe(false);
  });

  it('returns null when the dawg is unavailable (offline and uncached)', async () => {
    mockedGetDawg.mockResolvedValue(null);
    expect(await localWordCheck('scrabble_en', 'v1', 'AB')).toBe(null);
  });

  it('encodes the word to alphabet indices for the membership test', async () => {
    const indexOf = vi.fn(() => 0);
    mockedGetDawg.mockResolvedValue({ indexOf } as never);
    await localWordCheck('scrabble_en', 'v1', 'CAB');
    expect(indexOf).toHaveBeenCalledWith([2, 0, 1]);
  });

  it('loads the dawg for the pinned (variant, version)', async () => {
    mockedGetDawg.mockResolvedValue({ indexOf: () => 1 } as never);
    await localWordCheck('scrabble_en', 'v1.3.0', 'AB');
    expect(mockedGetDawg).toHaveBeenCalledWith('scrabble_en', 'v1.3.0');
  });
});
