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

import { parseDat, verifyHashesAgainstDat, DatDatabase } from '../../src/services/datVerifier';

const FIXTURE = path.resolve('tests/fixtures/sample.dat.xml');

describe('services/datVerifier', () => {
  it('parseDat parses simple DAT XML', () => {
    const xml = fs.readFileSync(FIXTURE, 'utf8');
    const dat: DatDatabase = parseDat(xml);

    expect(dat).toBeTruthy();
    expect(Array.isArray(dat.games)).toBe(true);
    expect(dat.games.length).toBe(2);

    const g0 = dat.games[0];
    expect(g0.name).toBe('Game Alpha');
    expect(g0.roms.length).toBeGreaterThan(0);
    expect(g0.roms[0].name).toBe('alpha1.bin');
    expect(g0.roms[0].crc).toBeDefined();
    expect(g0.roms[0].md5).toBeDefined();

    const g1 = dat.games[1];
    expect(g1.name).toBe('Game Beta');
    expect(g1.roms.some((r) => r.name === 'beta2.rom')).toBe(true);
  });

  it('verifyHashesAgainstDat finds match by CRC', () => {
    const xml = fs.readFileSync(FIXTURE, 'utf8');
    const dat = parseDat(xml);

    const match = verifyHashesAgainstDat(dat, { crc: 'DEADBEEF' });
    expect(match).not.toBeNull();
    expect(match?.gameName).toBe('Game Beta');
    expect(match?.romName).toBe('beta1.rom');
    expect(match?.matchedOn).toBe('crc');
  });

  it('verifyHashesAgainstDat finds match by MD5, SHA1 and size', () => {
    const xml = fs.readFileSync(FIXTURE, 'utf8');
    const dat = parseDat(xml);

    const md5match = verifyHashesAgainstDat(dat, { md5: '11111111111111111111111111111111' });
    expect(md5match).not.toBeNull();
    expect(md5match?.gameName).toBe('Game Alpha');
    expect(md5match?.romName).toBe('alpha1.bin');
    expect(md5match?.matchedOn).toBe('md5');

    const sha1match = verifyHashesAgainstDat(dat, {
      sha1: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
    });
    expect(sha1match).not.toBeNull();
    expect(sha1match?.gameName).toBe('Game Alpha');
    expect(sha1match?.romName).toBe('alpha2.bin');
    expect(sha1match?.matchedOn).toBe('sha1');

    const sizematch = verifyHashesAgainstDat(dat, { size: 4000 });
    expect(sizematch).not.toBeNull();
    expect(sizematch?.gameName).toBe('Game Beta');
    expect(sizematch?.romName).toBe('beta2.rom');
    expect(sizematch?.matchedOn).toBe('size');
  });

  it('verifyHashesAgainstDat returns null when no match', () => {
    const xml = fs.readFileSync(FIXTURE, 'utf8');
    const dat = parseDat(xml);

    const noMatch = verifyHashesAgainstDat(dat, { md5: 'ffffffffffffffffffffffffffffffff' });
    expect(noMatch).toBeNull();
  });
});
