import { Test } from '@nestjs/testing';
import {
  BadRequestException,
  ConflictException,
  NotFoundException,
} from '@nestjs/common';
import { CountriesService } from './countries.service';
import { PrismaService } from '../prisma/prisma.service';

describe('CountriesService', () => {
  let service: CountriesService;
  let prisma: PrismaService;
  const created: string[] = [];

  beforeAll(async () => {
    const moduleRef = await Test.createTestingModule({
      providers: [CountriesService, PrismaService],
    }).compile();
    service = moduleRef.get(CountriesService);
    prisma = moduleRef.get(PrismaService);
    await prisma.onModuleInit();
  });

  afterAll(async () => {
    if (created.length) {
      // Delete goods/origin_goods first so we can remove the countries.
      await prisma.good.deleteMany({
        where: { country: { countryName: { in: created } } },
      });
      await prisma.position.deleteMany({
        where: { country: { countryName: { in: created } } },
      });
      await prisma.country.deleteMany({
        where: { countryName: { in: created } },
      });
    }
    await prisma.onModuleDestroy();
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  it('creates and reads back a country', async () => {
    const name = `Test Country ${Date.now()}`;
    created.push(name);

    const createdRow = await service.create({ countryName: name });
    expect(createdRow.countryName).toBe(name);

    const fetched = await service.findOne(createdRow.id);
    expect(fetched.countryName).toBe(name);
  });

  it('rejects duplicate names with ConflictException', async () => {
    const name = `Dup Country ${Date.now()}`;
    created.push(name);
    await service.create({ countryName: name });
    await expect(service.create({ countryName: name })).rejects.toBeInstanceOf(
      ConflictException,
    );
  });

  it('throws NotFoundException for unknown id', async () => {
    await expect(service.findOne(BigInt(99999999))).rejects.toBeInstanceOf(
      NotFoundException,
    );
  });

  it('throws BadRequestException when deleting a country referenced by goods', async () => {
    const name = `Ref Country ${Date.now()}`;
    created.push(name);
    const country = await service.create({ countryName: name });

    // Need a category + origin good to satisfy the foreign keys before
    // we can attach a good that references the country.
    const category = await prisma.category.create({
      data: { categoryName: `Cat ${Date.now()}` },
    });
    const originGood = await prisma.originGood.create({
      data: { sdsGoodId: `sds-${Date.now()}-${Math.random()}` },
    });

    await prisma.good.create({
      data: {
        originGoodId: originGood.id,
        countryId: country.id,
        categoryId: category.id,
        goodName: 'sample',
      },
    });

    await expect(service.remove(country.id)).rejects.toBeInstanceOf(
      BadRequestException,
    );

    // cleanup
    await prisma.good.deleteMany({ where: { countryId: country.id } });
    await prisma.originGood.delete({ where: { id: originGood.id } });
    await prisma.category.delete({ where: { id: category.id } });
  });

  it('updates fields and deletes when unreferenced', async () => {
    const name = `Upd Country ${Date.now()}`;
    created.push(name);
    const c = await service.create({ countryName: name });
    const updated = await service.update(c.id, { countryName: `${name}-v2` });
    expect(updated.countryName).toBe(`${name}-v2`);
    created[created.indexOf(name)] = `${name}-v2`;

    await service.remove(c.id);
    const idx = created.indexOf(`${name}-v2`);
    if (idx !== -1) created.splice(idx, 1);
  });
});
