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

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

  beforeEach(async () => {
    app = buildApp();
    await app.ready();
    // Limpiar base de datos antes de cada test
    // Orden importante: relaciones de FK primero
    await prisma.romFile.deleteMany();
    await prisma.purchase.deleteMany();
    await prisma.gamePlatform.deleteMany();
    await prisma.artwork.deleteMany();
    await prisma.priceHistory.deleteMany();
    await prisma.game.deleteMany();
    await prisma.platform.deleteMany();
  });

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

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

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

    it('debería devolver una lista de juegos con todas sus propiedades', async () => {
      // Crear un juego de prueba
      const platform = await prisma.platform.create({
        data: { name: 'Nintendo', slug: 'nintendo' },
      });

      const game = await prisma.game.create({
        data: {
          title: 'The Legend of Zelda',
          slug: 'legend-of-zelda',
          description: 'Un videojuego clásico',
          gamePlatforms: {
            create: {
              platformId: platform.id,
            },
          },
          purchases: {
            create: {
              priceCents: 5000,
              currency: 'USD',
              store: 'eBay',
              date: new Date('2025-01-15'),
            },
          },
        },
        include: {
          gamePlatforms: {
            include: {
              platform: true,
            },
          },
          purchases: true,
        },
      });

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

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

  describe('POST /api/games', () => {
    it('debería crear un juego válido con todos los campos', async () => {
      // Crear plataforma primero
      const platform = await prisma.platform.create({
        data: { name: 'Nintendo 64', slug: 'n64' },
      });

      const payload = {
        title: 'Super Mario 64',
        platformId: platform.id,
        description: 'Notas sobre el juego',
        priceCents: 15000,
        currency: 'USD',
        store: 'Local Shop',
        date: '2025-01-20',
        condition: 'CIB',
      };

      const res = await app.inject({
        method: 'POST',
        url: '/api/games',
        payload,
      });

      expect(res.statusCode).toBe(201);
      const body = res.json();
      expect(body).toHaveProperty('id');
      expect(body.title).toBe('Super Mario 64');
      expect(body.description).toBe('Notas sobre el juego');
    });

    it('debería fallar si falta el título (requerido)', async () => {
      const res = await app.inject({
        method: 'POST',
        url: '/api/games',
        payload: {
          platformId: 'non-existing-id',
          priceCents: 10000,
        },
      });

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

    it('debería fallar si el título está vacío', async () => {
      const res = await app.inject({
        method: 'POST',
        url: '/api/games',
        payload: {
          title: '',
          platformId: 'some-id',
        },
      });

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

    it('debería crear un juego con solo los campos requeridos', async () => {
      const res = await app.inject({
        method: 'POST',
        url: '/api/games',
        payload: {
          title: 'Game Title Only',
        },
      });

      expect(res.statusCode).toBe(201);
      const body = res.json();
      expect(body).toHaveProperty('id');
      expect(body.title).toBe('Game Title Only');
    });
  });

  describe('PUT /api/games/:id', () => {
    it('debería actualizar un juego existente', async () => {
      const game = await prisma.game.create({
        data: {
          title: 'Original Title',
          slug: 'original-title',
        },
      });

      const res = await app.inject({
        method: 'PUT',
        url: `/api/games/${game.id}`,
        payload: {
          title: 'Updated Title',
          description: 'Updated description',
        },
      });

      expect(res.statusCode).toBe(200);
      const body = res.json();
      expect(body.title).toBe('Updated Title');
      expect(body.description).toBe('Updated description');
    });

    it('debería devolver 404 si el juego no existe', async () => {
      const res = await app.inject({
        method: 'PUT',
        url: '/api/games/non-existing-id',
        payload: {
          title: 'Some Title',
        },
      });

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

    it('debería permitir actualización parcial', async () => {
      const game = await prisma.game.create({
        data: {
          title: 'Original Title',
          slug: 'original',
          description: 'Original description',
        },
      });

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

      expect(res.statusCode).toBe(200);
      const body = res.json();
      expect(body.title).toBe('Original Title'); // No cambió
      expect(body.description).toBe('New description only'); // Cambió
    });
  });

  describe('DELETE /api/games/:id', () => {
    it('debería eliminar un juego existente', async () => {
      const game = await prisma.game.create({
        data: {
          title: 'Game to Delete',
          slug: 'game-to-delete',
        },
      });

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

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

      // Verificar que el juego fue eliminado
      const deletedGame = await prisma.game.findUnique({
        where: { id: game.id },
      });
      expect(deletedGame).toBeNull();
    });

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

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

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