import { MarketsService } from './markets.service';

function selection(selectionCode: string, odds = 1.9) {
  return {
    selectionCode,
    selectionName: selectionCode,
    odds,
    status: 'OPEN',
  };
}

function errorCode(error: unknown) {
  const response = (error as { getResponse?: () => unknown }).getResponse?.();
  return (response as { code?: string } | undefined)?.code;
}

function createPrismaMock() {
  let marketId = 100n;
  let selectionId = 1000n;
  return {
    match: {
      findUnique: jest.fn().mockResolvedValue({ id: 1n }),
    },
    market: {
      findFirst: jest.fn().mockResolvedValue(null),
      create: jest.fn().mockImplementation(async ({ data }) => ({ id: marketId++, ...data })),
      update: jest.fn().mockImplementation(async ({ where, data }) => ({ id: where.id, ...data })),
      findUnique: jest.fn().mockImplementation(async ({ where }) => ({ id: where.id, selections: [] })),
      findMany: jest.fn().mockResolvedValue([]),
      updateMany: jest.fn().mockResolvedValue({ count: 0 }),
    },
    marketSelection: {
      findMany: jest.fn().mockResolvedValue([]),
      create: jest.fn().mockImplementation(async ({ data }) => ({ id: selectionId++, ...data })),
      update: jest.fn(),
      updateMany: jest.fn().mockResolvedValue({ count: 0 }),
    },
    oddsChangeLog: {
      create: jest.fn(),
    },
  };
}

describe('MarketsService line value rules', () => {
  it('exposes usesLineValue in market definitions', () => {
    const service = new MarketsService(createPrismaMock() as never);

    const definitions = service.listMarketDefinitions();

    expect(definitions.find((d) => d.marketType === 'FT_HANDICAP')?.usesLineValue).toBe(true);
    expect(definitions.find((d) => d.marketType === 'FT_1X2')?.usesLineValue).toBe(false);
  });

  it('rejects line markets without a numeric line value', async () => {
    const service = new MarketsService(createPrismaMock() as never);

    let caughtCode: string | undefined;
    try {
      await service.saveMatchMarkets(1n, [
        {
          marketType: 'FT_HANDICAP',
          lineValue: null,
          selections: [selection('HOME'), selection('AWAY')],
        },
      ]);
    } catch (error) {
      caughtCode = errorCode(error);
    }
    expect(caughtCode).toBe('MARKET_LINE_REQUIRED');
  });

  it('rejects non-line markets with a line value', async () => {
    const service = new MarketsService(createPrismaMock() as never);

    let caughtCode: string | undefined;
    try {
      await service.saveMatchMarkets(1n, [
        {
          marketType: 'FT_1X2',
          lineValue: 1,
          selections: [selection('HOME'), selection('DRAW'), selection('AWAY')],
        },
      ]);
    } catch (error) {
      caughtCode = errorCode(error);
    }
    expect(caughtCode).toBe('MARKET_LINE_NOT_ALLOWED');
  });

  it('allows non-line markets with null line value', async () => {
    const prisma = createPrismaMock();
    const service = new MarketsService(prisma as never);

    const result = await service.saveMatchMarkets(1n, [
      {
        marketType: 'FT_1X2',
        lineValue: null,
        selections: [selection('HOME'), selection('DRAW'), selection('AWAY')],
      },
    ]);

    expect(result).toEqual({ updated: 1, closed: 0 });
    expect(prisma.market.create).toHaveBeenCalledWith(
      expect.objectContaining({
        data: expect.objectContaining({
          marketType: 'FT_1X2',
          lineKey: 'FT_1X2:none',
          lineValue: null,
        }),
      }),
    );
  });

  it('keeps distinct line keys for copied line markets', async () => {
    const prisma = createPrismaMock();
    const service = new MarketsService(prisma as never);

    const result = await service.saveMatchMarkets(1n, [
      {
        marketType: 'FT_HANDICAP',
        lineValue: -0.5,
        selections: [selection('HOME'), selection('AWAY')],
      },
      {
        marketType: 'FT_HANDICAP',
        lineValue: -0.25,
        selections: [selection('HOME'), selection('AWAY')],
      },
    ]);

    expect(result).toEqual({ updated: 2, closed: 0 });
    expect(prisma.market.create.mock.calls.map(([arg]) => arg.data.lineKey)).toEqual([
      'FT_HANDICAP:-0.50',
      'FT_HANDICAP:-0.25',
    ]);
  });
});
