import { beforeEach, expect, test } from 'bun:test';

import { prismaMock, uuidV7Mock } from '../support/prisma.mock';

const { createSport, getSportById, listSports, updateSport } = await import(
  '@/modules/sport/services/sport.service'
);

beforeEach(() => {
  prismaMock._reset();
  uuidV7Mock.mockClear();
});

test('listSports returns sports ordered by name', async () => {
  const sports = [
    {
      id: 'sport-2',
      name: 'Tenis',
      slug: 'tenis',
      isActive: true,
      createdAt: new Date('2026-04-22T00:00:00.000Z'),
      updatedAt: new Date('2026-04-22T00:00:00.000Z'),
    },
    {
      id: 'sport-1',
      name: 'Básquet',
      slug: 'basquet',
      isActive: true,
      createdAt: new Date('2026-04-21T00:00:00.000Z'),
      updatedAt: new Date('2026-04-21T00:00:00.000Z'),
    },
  ];

  prismaMock.sport.findMany.mockResolvedValue(sports as never);

  const result = await listSports();

  expect(prismaMock.sport.findMany).toHaveBeenCalledWith({
    orderBy: { name: 'asc' },
  });
  expect(result).toEqual({
    ok: true,
    value: sports,
  });
});

test('getSportById returns the requested sport', async () => {
  const sport = {
    id: 'sport-1',
    name: 'Tenis',
    slug: 'tenis',
    isActive: true,
    createdAt: new Date('2026-04-22T00:00:00.000Z'),
    updatedAt: new Date('2026-04-22T00:00:00.000Z'),
  };

  prismaMock.sport.findUnique.mockResolvedValue(sport as never);

  const result = await getSportById('sport-1');

  expect(prismaMock.sport.findUnique).toHaveBeenCalledWith({
    where: { id: 'sport-1' },
  });
  expect(result).toEqual(sport);
});

test('createSport trims the name and creates a unique slug', async () => {
  const createdSport = {
    id: '00000000-0000-4000-8000-000000000001',
    name: 'Fútbol 7!!',
    slug: 'futbol-7',
    isActive: true,
    createdAt: new Date('2026-04-23T00:00:00.000Z'),
    updatedAt: new Date('2026-04-23T00:00:00.000Z'),
  };

  prismaMock.sport.findFirst.mockResolvedValue(null as never);
  prismaMock.sport.count.mockResolvedValue(0 as never);
  prismaMock.sport.create.mockResolvedValue(createdSport as never);

  const result = await createSport({ name: '  Fútbol 7!!  ' });

  expect(uuidV7Mock).toHaveBeenCalledTimes(1);
  expect(prismaMock.sport.findFirst).toHaveBeenCalledWith({
    where: { slug: 'futbol-7' },
    select: { id: true },
  });
  expect(prismaMock.sport.count).toHaveBeenCalledWith({
    where: { slug: 'futbol-7' },
  });
  expect(prismaMock.sport.create).toHaveBeenCalledWith({
    data: {
      id: '00000000-0000-4000-8000-000000000001',
      name: 'Fútbol 7!!',
      slug: 'futbol-7',
      isActive: true,
    },
  });
  expect(result).toEqual({
    ok: true,
    value: createdSport,
  });
});

test('createSport retries with a numeric suffix when the slug already exists', async () => {
  const createdSport = {
    id: '00000000-0000-4000-8000-000000000001',
    name: 'Tenis',
    slug: 'tenis-2',
    isActive: true,
    createdAt: new Date('2026-04-23T00:00:00.000Z'),
    updatedAt: new Date('2026-04-23T00:00:00.000Z'),
  };

  prismaMock.sport.findFirst
    .mockResolvedValueOnce({ id: 'existing-sport' } as never)
    .mockResolvedValueOnce(null as never);
  prismaMock.sport.count.mockResolvedValue(0 as never);
  prismaMock.sport.create.mockResolvedValue(createdSport as never);

  const result = await createSport({ name: 'Tenis' });

  expect(prismaMock.sport.findFirst).toHaveBeenNthCalledWith(1, {
    where: { slug: 'tenis' },
    select: { id: true },
  });
  expect(prismaMock.sport.findFirst).toHaveBeenNthCalledWith(2, {
    where: { slug: 'tenis-2' },
    select: { id: true },
  });
  expect(prismaMock.sport.create).toHaveBeenCalledWith({
    data: {
      id: '00000000-0000-4000-8000-000000000001',
      name: 'Tenis',
      slug: 'tenis-2',
      isActive: true,
    },
  });
  expect(result).toEqual({
    ok: true,
    value: createdSport,
  });
});

test('updateSport updates the name, slug and active flag', async () => {
  const updatedSport = {
    id: 'sport-1',
    name: 'Básquet 3x3',
    slug: 'basquet-3x3',
    isActive: false,
    createdAt: new Date('2026-04-21T00:00:00.000Z'),
    updatedAt: new Date('2026-04-23T00:00:00.000Z'),
  };

  prismaMock.sport.findFirst.mockResolvedValue(null as never);
  prismaMock.sport.update.mockResolvedValue(updatedSport as never);

  const result = await updateSport('sport-1', {
    name: 'Básquet 3x3',
    isActive: false,
  });

  expect(prismaMock.sport.findFirst).toHaveBeenCalledWith({
    where: {
      slug: 'basquet-3x3',
      id: {
        not: 'sport-1',
      },
    },
    select: { id: true },
  });
  expect(prismaMock.sport.update).toHaveBeenCalledWith({
    where: { id: 'sport-1' },
    data: {
      name: 'Básquet 3x3',
      slug: 'basquet-3x3',
      isActive: false,
    },
  });
  expect(result).toEqual(updatedSport);
});
