import { AiTraceService } from './ai-trace.service';

describe('AiTraceService receipt masking', () => {
  const prismaMock = {
    aiTrace: {
      findFirst: jest.fn(),
      findMany: jest.fn(),
    },
    flyerSession: {
      findMany: jest.fn(),
      findUnique: jest.fn(),
    },
  };

  const service = new AiTraceService(prismaMock as any);

  beforeEach(() => {
    jest.clearAllMocks();
  });

  it('masks sensitive data in receipt prompt and rawOutput', async () => {
    prismaMock.aiTrace.findFirst.mockResolvedValue({
      id: 42,
      source: 'receipt',
      status: 'success',
      createdAt: new Date('2026-05-21T10:00:00.000Z'),
      userId: 7,
      sessionId: null,
      model: 'importer-receipt-ai',
      durationMs: 240,
      error: null,
      prompt: 'Kund email anna@example.com och telefon 070-123 45 67',
      rawOutput: JSON.stringify({
        personnummer: '850101-1234',
        email: 'anna@example.com',
        nested: {
          namn: 'Anna Andersson',
          phone: '+46701234567',
        },
      }),
      normalizedOutput: {
        items: [
          {
            rawName: 'Mjolk',
            customerEmail: 'anna@example.com',
          },
        ],
      },
      user: {
        username: 'admin',
        email: 'admin@example.com',
      },
    });

    const result = await service.getTraceById('receipt-42');

    expect(result.prompt).not.toContain('anna@example.com');
    expect(result.prompt).not.toContain('070-123 45 67');
    expect(result.prompt).toContain('[MASKED]');

    expect(result.rawOutput).not.toContain('850101-1234');
    expect(result.rawOutput).not.toContain('anna@example.com');
    expect(result.rawOutput).not.toContain('Anna Andersson');
    expect(result.rawOutput).toContain('[MASKED]');

    expect(result.normalizedOutput).toEqual({
      items: [
        {
          rawName: 'Mjolk',
          customerEmail: '[MASKED]',
        },
      ],
    });
  });

  it('filters flyer list by errors in database query', async () => {
    prismaMock.flyerSession.findMany.mockResolvedValue([]);

    await service.listTraces({
      source: 'flyer',
      limit: 20,
      onlyErrors: true,
    });

    expect(prismaMock.flyerSession.findMany).toHaveBeenCalledWith(
      expect.objectContaining({
        where: expect.objectContaining({
          items: { none: {} },
        }),
      }),
    );
  });

  it('returns flyer prompt/rawOutput and trace counters from aiTrace supplement', async () => {
    prismaMock.flyerSession.findUnique.mockResolvedValue({
      id: 101,
      userId: 7,
      createdAt: new Date('2026-05-21T12:00:00.000Z'),
      sourceFileName: 'willys.pdf',
      sourceMimeType: 'application/pdf',
      sourceFileSize: 12345,
      user: { username: 'admin', email: 'admin@example.com' },
      items: [
        {
          id: 1,
          rawName: 'Tomat',
          normalizedName: 'tomat',
          brand: null,
          categoryHint: 'Grönsaker',
          categoryId: null,
          price: null,
          priceUnit: null,
          comparisonPrice: null,
          comparisonUnit: null,
          weight: null,
          bundleWeight: null,
          isBundle: false,
          bundleItems: [],
          offerText: null,
          parseConfidence: 0.9,
          parseReasons: ['low_confidence'],
          matchedProductId: null,
          matchedProductName: null,
          matchedVia: 'none',
          matchConfidence: null,
          matchReasons: [],
        },
      ],
    });

    prismaMock.aiTrace.findMany.mockResolvedValue([
      {
        sessionId: 101,
        prompt: 'Flyer prompt med email kund@example.com',
        rawOutput: '{"ok":true}',
        normalizedOutput: { retryCount: 2, chunkCount: 4 },
      },
    ]);

    const result = await service.getTraceById('flyer-101');

    expect(result.prompt).toContain('[MASKED]');
    expect(result.rawOutput).toContain('{"ok":true}');
    expect(result.retryCount).toBe(2);
    expect(result.chunkCount).toBe(4);
    expect(result.warnings).toContain('parse:low_confidence');
  });
});
