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

import { Errors } from '@/lib/errors';
import { err, ok } from '@/lib/result';
import type { CreateSportInput } from '@repo/api-contract';

const createSportMock = mock(async (_input: CreateSportInput) =>
  ok({
    id: 'sport-1',
    name: 'Tenis',
    slug: 'tenis',
    isActive: true,
    createdAt: '2026-04-23T00:00:00.000Z',
    updatedAt: '2026-04-23T00:00:00.000Z',
  })
);

mock.module('@/modules/sport/services/sport.service', () => ({
  __esModule: true,
  createSport: createSportMock,
}));

const { createSportHandler } = await import('@/modules/sport/handlers/create-sport.handler');

type HandlerContext = {
  get: (key: 'requestId') => string | undefined;
  req: {
    valid: () => unknown;
  };
  json: ReturnType<typeof mock>;
};

function createContext(body: unknown) {
  const json = mock((payload: unknown, init?: unknown) => ({
    payload,
    init,
  }));

  const c = {
    get: () => undefined,
    req: {
      valid: () => body,
    },
    json,
  } as unknown as HandlerContext;

  return { c, json };
}

beforeEach(() => {
  createSportMock.mockReset();
});

test('returns 201 with the created sport', async () => {
  const createdSport = {
    id: 'sport-1',
    name: 'Tenis',
    slug: 'tenis',
    isActive: true,
    createdAt: '2026-04-23T00:00:00.000Z',
    updatedAt: '2026-04-23T00:00:00.000Z',
  } as const;

  createSportMock.mockResolvedValue(ok(createdSport));

  const payload: CreateSportInput = { name: '  Tenis  ' };
  const { c, json } = createContext(payload);

  const response = await createSportHandler(c as never);

  expect(createSportMock).toHaveBeenCalledWith(payload);
  expect(json.mock.calls[0]?.[0]).toEqual(createdSport);
  expect(json.mock.calls[0]?.[1]).toBe(201);
  expect(response).toBeDefined();
});

test('returns a conflict problem when the service rejects with a conflict error', async () => {
  createSportMock.mockResolvedValue(err(Errors.conflict('Ya existe un deporte con ese nombre.')));

  const payload: CreateSportInput = { name: 'Tenis' };
  const { c, json } = createContext(payload);

  const response = await createSportHandler(c as never);

  expect(createSportMock).toHaveBeenCalledWith(payload);
  expect(json.mock.calls[0]?.[0]).toEqual({
    type: 'https://api.myapp.dev/problems/conflict',
    title: 'Conflict',
    status: 409,
    detail: 'Ya existe un deporte con ese nombre.',
  });
  expect(json.mock.calls[0]?.[1]).toBe(409);
  expect(response).toBeDefined();
});
