import { Test } from '@nestjs/testing';
import { ConflictException, NotFoundException } from '@nestjs/common';
import { TagGroupsService } from './tag-groups.service';
import { PrismaService } from '../prisma/prisma.service';

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

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

  afterAll(async () => {
    if (createdNames.length) {
      await prisma.tagGroup.deleteMany({ where: { groupName: { in: createdNames } } });
    }
    await prisma.onModuleDestroy();
  });

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

  it('creates and finds a tag group', async () => {
    const name = `Group ${Date.now()}`;
    createdNames.push(name);
    const created = await service.create({ groupName: name, sortOrder: 99 });
    expect(created.groupName).toBe(name);
    expect(created.sortOrder).toBe(99);

    const found = await service.findOne(created.id);
    expect(found.groupName).toBe(name);
  });

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

  it('updates group name and color', async () => {
    const name = `Upd ${Date.now()}`;
    createdNames.push(name);
    const g = await service.create({ groupName: name });
    const updated = await service.update(g.id, {
      groupName: `${name}-v2`,
      groupColor: '#FF8800',
    });
    expect(updated.groupName).toBe(`${name}-v2`);
    expect(updated.groupColor).toBe('#FF8800');
  });

  it('reorders multiple groups', async () => {
    const a = `Reorder A ${Date.now()}`;
    const b = `Reorder B ${Date.now()}`;
    createdNames.push(a, b);
    const ga = await service.create({ groupName: a, sortOrder: 1 });
    const gb = await service.create({ groupName: b, sortOrder: 2 });

    await service.reorder({
      items: [
        { id: Number(ga.id), sortOrder: 5 },
        { id: Number(gb.id), sortOrder: 6 },
      ],
    });

    const refreshedA = await prisma.tagGroup.findUnique({ where: { id: ga.id } });
    const refreshedB = await prisma.tagGroup.findUnique({ where: { id: gb.id } });
    expect(refreshedA!.sortOrder).toBe(5);
    expect(refreshedB!.sortOrder).toBe(6);
  });

  it('throws NotFoundException for non-existent group', async () => {
    await expect(service.findOne(BigInt(999999999))).rejects.toBeInstanceOf(
      NotFoundException,
    );
  });

  it('removes a group; tags become ungrouped (SetNull)', async () => {
    const name = `Del ${Date.now()}`;
    createdNames.push(name);
    const g = await service.create({ groupName: name });

    // Create a tag assigned to it
    const tagName = `TagInGroup ${Date.now()}`;
    const tag = await prisma.tag.create({
      data: { tagName, tagGroupId: g.id },
    });

    await service.remove(g.id);

    const refreshedTag = await prisma.tag.findUnique({ where: { id: tag.id } });
    expect(refreshedTag).not.toBeNull();
    expect(refreshedTag!.tagGroupId).toBeNull();

    // cleanup
    await prisma.tag.delete({ where: { id: tag.id } });
  });
});
