import {
  CreateInvoiceData,
  Invoice,
  InvoiceID,
  InvoiceStats,
  DataContainer,
  InvoiceEnumStatus,
} from '../models/invoice';
import { InvoiceManager } from './invoice-manager';

const providerMock = {
  createInvoice: jest.fn(),
  cancelInvoice: jest.fn(),
  getInvoiceInfo: jest.fn(),
  getInvoiceStats: jest.fn(),
  isUpdateValid: jest.fn(),
};

describe('InvoiceManager', () => {
  let invoiceManager: InvoiceManager;

  beforeEach(() => {
    invoiceManager = new InvoiceManager(providerMock);
  });

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

  it('should call createInvoice method on provider', async () => {
    const createInvoiceData: CreateInvoiceData = {
      order_id: 1,
      amount: 1,
    };
    const expectedInvoice: DataContainer<Invoice> = {
      data: {
        id: 1,
        order_id: BigInt(1),
        amount: BigInt(1),
      } as Invoice,
      isValid: true,
    };

    providerMock.createInvoice.mockResolvedValue(expectedInvoice);

    const invoice = await invoiceManager.create(createInvoiceData);

    expect(providerMock.createInvoice).toHaveBeenCalledWith(createInvoiceData);
    expect(invoice).toBe(expectedInvoice);
  });

  it('should call cancelInvoice method on provider', async () => {
    const invoiceId: InvoiceID = 1;
    const expectedInvoice: DataContainer<Invoice> = {
      data: {
        id: 1,
        order_id: BigInt(1),
        amount: BigInt(1),
        status: InvoiceEnumStatus.canceled,
      } as Invoice,
      isValid: true,
    };

    providerMock.cancelInvoice.mockResolvedValue(expectedInvoice);

    const invoice = await invoiceManager.cancel(invoiceId);

    expect(providerMock.cancelInvoice).toHaveBeenCalledWith(invoiceId);
    expect(invoice).toBe(expectedInvoice);
  });

  it('should call getInvoiceInfo method on provider', async () => {
    const invoiceId: InvoiceID = 1;
    const expectedInvoice: DataContainer<Invoice> = {
      data: {
        id: 1,
        order_id: BigInt(1),
        amount: BigInt(1),
        status: InvoiceEnumStatus.created,
      } as Invoice,
      isValid: true,
    };

    providerMock.getInvoiceInfo.mockResolvedValue(expectedInvoice);

    const invoice = await invoiceManager.info(invoiceId);

    expect(providerMock.getInvoiceInfo).toHaveBeenCalledWith(invoiceId);

    expect(invoice).toBe(expectedInvoice);
  });

  it('should call getInvoiceStats method on provider', async () => {
    const expectedStats: InvoiceStats = {
      count: 1,
      invoice_sum: 10,
    };

    providerMock.getInvoiceStats.mockResolvedValue(expectedStats);

    const stats = await invoiceManager.stats();

    expect(providerMock.getInvoiceStats).toHaveBeenCalled();

    expect(stats).toBe(expectedStats);
  });
});
