import { describe, it, expect, vi, beforeEach } from 'vitest';
import { RecordPriceHistoryHandler } from '../event-handlers/record-price-history.handler';
import { ListingPriceChangedEvent } from '../../domain/events/listing-price-changed.event';

describe('RecordPriceHistoryHandler', () => {
  let handler: RecordPriceHistoryHandler;
  let mockPrisma: { priceHistory: { create: ReturnType<typeof vi.fn> } };
  let mockLogger: { debug: ReturnType<typeof vi.fn>; error: ReturnType<typeof vi.fn> };

  beforeEach(() => {
    mockPrisma = {
      priceHistory: { create: vi.fn().mockResolvedValue({ id: 'ph-1' }) },
    };
    mockLogger = {
      debug: vi.fn(),
      error: vi.fn(),
    };
    handler = new RecordPriceHistoryHandler(mockPrisma as any, mockLogger as any);
  });

  it('should persist a price history record with correct data', async () => {
    const event = new ListingPriceChangedEvent(
      'listing-1',
      5_000_000_000n,
      6_000_000_000n,
      'manual_update',
    );

    await handler.handle(event);

    expect(mockPrisma.priceHistory.create).toHaveBeenCalledWith({
      data: {
        listingId: 'listing-1',
        oldPrice: 5_000_000_000n,
        newPrice: 6_000_000_000n,
        source: 'manual_update',
        changedAt: event.occurredAt,
      },
    });
  });

  it('should persist source as admin_override when provided', async () => {
    const event = new ListingPriceChangedEvent(
      'listing-2',
      3_000_000_000n,
      4_500_000_000n,
      'admin_override',
    );

    await handler.handle(event);

    expect(mockPrisma.priceHistory.create).toHaveBeenCalledWith(
      expect.objectContaining({
        data: expect.objectContaining({ source: 'admin_override' }),
      }),
    );
  });

  it('should default source to manual_update', async () => {
    const event = new ListingPriceChangedEvent('listing-3', 1_000_000n, 2_000_000n);

    await handler.handle(event);

    expect(mockPrisma.priceHistory.create).toHaveBeenCalledWith(
      expect.objectContaining({
        data: expect.objectContaining({ source: 'manual_update' }),
      }),
    );
  });

  it('should log debug message on success', async () => {
    const event = new ListingPriceChangedEvent('listing-1', 100n, 200n);

    await handler.handle(event);

    expect(mockLogger.debug).toHaveBeenCalledWith(
      expect.stringContaining('listing-1'),
      'RecordPriceHistoryHandler',
    );
  });

  it('should log error and not throw when persistence fails', async () => {
    mockPrisma.priceHistory.create.mockRejectedValue(new Error('DB connection lost'));
    const event = new ListingPriceChangedEvent('listing-1', 100n, 200n);

    await expect(handler.handle(event)).resolves.toBeUndefined();

    expect(mockLogger.error).toHaveBeenCalledWith(
      expect.stringContaining('DB connection lost'),
      expect.any(String),
      'RecordPriceHistoryHandler',
    );
  });
});
