import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { buildApp } from '../../src/app';
import { FastifyInstance } from 'fastify';
import { prisma } from '../../src/plugins/prisma';

describe('ROMs API', () => {
  let app: FastifyInstance;

  beforeEach(async () => {
    app = buildApp();
    await app.ready();
    // Limpiar base de datos antes de cada test (eliminar ROMs primero por foreign key)
    await prisma.romFile.deleteMany();
    await prisma.gamePlatform.deleteMany();
    await prisma.purchase.deleteMany();
    await prisma.artwork.deleteMany();
    await prisma.priceHistory.deleteMany();
    await prisma.game.deleteMany();
  });

  afterEach(async () => {
    await app.close();
  });

  describe('GET /api/roms', () => {
    it('debería devolver una lista vacía cuando no hay ROMs', async () => {
      const res = await app.inject({
        method: 'GET',
        url: '/api/roms',
      });

      expect(res.statusCode).toBe(200);
      expect(res.json()).toEqual([]);
    });

    it('debería devolver una lista de ROMs con sus propiedades', async () => {
      // Crear un ROM de prueba
      const rom = await prisma.romFile.create({
        data: {
          path: '/roms/games/',
          filename: 'game.zip',
          checksum: 'abc123def456',
          size: 1024,
          format: 'zip',
        },
      });

      const res = await app.inject({
        method: 'GET',
        url: '/api/roms',
      });

      expect(res.statusCode).toBe(200);
      const body = res.json();
      expect(Array.isArray(body)).toBe(true);
      expect(body.length).toBe(1);
      expect(body[0].id).toBe(rom.id);
      expect(body[0].filename).toBe('game.zip');
    });

    it('debería incluir información del juego asociado', async () => {
      const game = await prisma.game.create({
        data: {
          title: 'Test Game',
          slug: 'test-game',
        },
      });

      const rom = await prisma.romFile.create({
        data: {
          path: '/roms/',
          filename: 'test-with-game.zip',
          checksum: 'checksum-game-123',
          size: 2048,
          format: 'zip',
          gameId: game.id,
        },
      });

      const res = await app.inject({
        method: 'GET',
        url: '/api/roms',
      });

      expect(res.statusCode).toBe(200);
      const body = res.json();
      // Buscar el ROM que creamos por checksum
      const createdRom = body.find((r: any) => r.checksum === 'checksum-game-123');
      expect(createdRom).toBeDefined();
      expect(createdRom.game).toBeDefined();
      expect(createdRom.game.title).toBe('Test Game');
    });
  });

  describe('GET /api/roms/:id', () => {
    it('debería retornar un ROM existente', async () => {
      const rom = await prisma.romFile.create({
        data: {
          path: '/roms/',
          filename: 'game1.zip',
          checksum: 'checksum1',
          size: 1024,
          format: 'zip',
        },
      });

      const res = await app.inject({
        method: 'GET',
        url: `/api/roms/${rom.id}`,
      });

      expect(res.statusCode).toBe(200);
      const body = res.json();
      expect(body.id).toBe(rom.id);
      expect(body.filename).toBe('game1.zip');
    });

    it('debería retornar 404 si el ROM no existe', async () => {
      const res = await app.inject({
        method: 'GET',
        url: '/api/roms/non-existing-id',
      });

      expect(res.statusCode).toBe(404);
      expect(res.json()).toHaveProperty('error');
    });

    it('debería incluir el juego asociado al ROM', async () => {
      const game = await prisma.game.create({
        data: {
          title: 'Zelda',
          slug: 'zelda',
        },
      });

      const rom = await prisma.romFile.create({
        data: {
          path: '/roms/',
          filename: 'zelda.zip',
          checksum: 'checksum2',
          size: 2048,
          format: 'zip',
          gameId: game.id,
        },
      });

      const res = await app.inject({
        method: 'GET',
        url: `/api/roms/${rom.id}`,
      });

      expect(res.statusCode).toBe(200);
      const body = res.json();
      expect(body.game).toBeDefined();
      expect(body.game.title).toBe('Zelda');
    });
  });

  describe('PUT /api/roms/:id/game', () => {
    it('debería vincular un juego a un ROM existente', async () => {
      const game = await prisma.game.create({
        data: {
          title: 'Mario',
          slug: 'mario',
        },
      });

      const rom = await prisma.romFile.create({
        data: {
          path: '/roms/',
          filename: 'mario.zip',
          checksum: 'checksum3',
          size: 512,
          format: 'zip',
        },
      });

      const res = await app.inject({
        method: 'PUT',
        url: `/api/roms/${rom.id}/game`,
        payload: {
          gameId: game.id,
        },
      });

      expect(res.statusCode).toBe(200);
      const body = res.json();
      expect(body.gameId).toBe(game.id);
      expect(body.game.title).toBe('Mario');
    });

    it('debería devolver 400 si el gameId es inválido', async () => {
      const rom = await prisma.romFile.create({
        data: {
          path: '/roms/',
          filename: 'game.zip',
          checksum: 'checksum4',
          size: 1024,
          format: 'zip',
        },
      });

      const res = await app.inject({
        method: 'PUT',
        url: `/api/roms/${rom.id}/game`,
        payload: {
          gameId: 'invalid-game-id',
        },
      });

      expect(res.statusCode).toBe(400);
    });

    it('debería devolver 404 si el ROM no existe', async () => {
      const game = await prisma.game.create({
        data: {
          title: 'Test',
          slug: 'test',
        },
      });

      const res = await app.inject({
        method: 'PUT',
        url: '/api/roms/non-existing-id/game',
        payload: {
          gameId: game.id,
        },
      });

      expect(res.statusCode).toBe(404);
    });

    it('debería devolver 400 si falta gameId', async () => {
      const rom = await prisma.romFile.create({
        data: {
          path: '/roms/',
          filename: 'game.zip',
          checksum: 'checksum5',
          size: 1024,
          format: 'zip',
        },
      });

      const res = await app.inject({
        method: 'PUT',
        url: `/api/roms/${rom.id}/game`,
        payload: {},
      });

      expect(res.statusCode).toBe(400);
    });
  });

  describe('DELETE /api/roms/:id', () => {
    it('debería eliminar un ROM existente', async () => {
      const rom = await prisma.romFile.create({
        data: {
          path: '/roms/',
          filename: 'delete-me.zip',
          checksum: 'checksum6',
          size: 1024,
          format: 'zip',
        },
      });

      const res = await app.inject({
        method: 'DELETE',
        url: `/api/roms/${rom.id}`,
      });

      expect(res.statusCode).toBe(204);

      // Verificar que el ROM fue eliminado
      const deletedRom = await prisma.romFile.findUnique({
        where: { id: rom.id },
      });
      expect(deletedRom).toBeNull();
    });

    it('debería devolver 404 si el ROM no existe', async () => {
      const res = await app.inject({
        method: 'DELETE',
        url: '/api/roms/non-existing-id',
      });

      expect(res.statusCode).toBe(404);
    });
  });
});

/**
 * Metadatos:
 * Autor: GitHub Copilot
 * Última actualización: 2026-02-11
 */
