import { UpdateMemberPaymentPresenter } from './UpdateMemberPaymentPresenter';
import { UpdateMemberPaymentResultDTO } from '../dtos/UpdateMemberPaymentDTO';
import { MemberPaymentStatus } from '../dtos/MemberPaymentStatus';

describe('UpdateMemberPaymentPresenter', () => {
  let presenter: UpdateMemberPaymentPresenter;

  beforeEach(() => {
    presenter = new UpdateMemberPaymentPresenter();
  });

  describe('present', () => {
    it('should store the result', () => {
      const result: UpdateMemberPaymentResultDTO = {
        payment: {
          id: 'payment-123',
          feeId: 'fee-123',
          driverId: 'driver-123',
          amount: 100,
          platformFee: 5,
          netAmount: 95,
          status: MemberPaymentStatus.PAID,
          dueDate: new Date('2024-01-01'),
          paidAt: new Date('2024-01-02'),
        },
      };

      presenter.present(result);

      expect(presenter.getResponseModel()).toEqual(result);
    });

    it('should overwrite previous result', () => {
      const firstResult: UpdateMemberPaymentResultDTO = {
        payment: {
          id: 'payment-123',
          feeId: 'fee-123',
          driverId: 'driver-123',
          amount: 100,
          platformFee: 5,
          netAmount: 95,
          status: MemberPaymentStatus.PAID,
          dueDate: new Date('2024-01-01'),
          paidAt: new Date('2024-01-02'),
        },
      };

      const secondResult: UpdateMemberPaymentResultDTO = {
        payment: {
          id: 'payment-456',
          feeId: 'fee-456',
          driverId: 'driver-456',
          amount: 200,
          platformFee: 10,
          netAmount: 190,
          status: MemberPaymentStatus.OVERDUE,
          dueDate: new Date('2024-01-03'),
        },
      };

      presenter.present(firstResult);
      presenter.present(secondResult);

      expect(presenter.getResponseModel()).toEqual(secondResult);
    });
  });

  describe('getResponseModel', () => {
    it('should return null when not presented', () => {
      expect(presenter.getResponseModel()).toBeNull();
    });

    it('should return the result after present()', () => {
      const result: UpdateMemberPaymentResultDTO = {
        payment: {
          id: 'payment-123',
          feeId: 'fee-123',
          driverId: 'driver-123',
          amount: 100,
          platformFee: 5,
          netAmount: 95,
          status: MemberPaymentStatus.PAID,
          dueDate: new Date('2024-01-01'),
          paidAt: new Date('2024-01-02'),
        },
      };

      presenter.present(result);

      expect(presenter.getResponseModel()).toEqual(result);
    });
  });

  describe('reset', () => {
    it('should clear the result', () => {
      const result: UpdateMemberPaymentResultDTO = {
        payment: {
          id: 'payment-123',
          feeId: 'fee-123',
          driverId: 'driver-123',
          amount: 100,
          platformFee: 5,
          netAmount: 95,
          status: MemberPaymentStatus.PAID,
          dueDate: new Date('2024-01-01'),
          paidAt: new Date('2024-01-02'),
        },
      };

      presenter.present(result);
      presenter.reset();

      expect(presenter.getResponseModel()).toBeNull();
    });

    it('should allow presenting again after reset', () => {
      const firstResult: UpdateMemberPaymentResultDTO = {
        payment: {
          id: 'payment-123',
          feeId: 'fee-123',
          driverId: 'driver-123',
          amount: 100,
          platformFee: 5,
          netAmount: 95,
          status: MemberPaymentStatus.PAID,
          dueDate: new Date('2024-01-01'),
          paidAt: new Date('2024-01-02'),
        },
      };

      const secondResult: UpdateMemberPaymentResultDTO = {
        payment: {
          id: 'payment-456',
          feeId: 'fee-456',
          driverId: 'driver-456',
          amount: 200,
          platformFee: 10,
          netAmount: 190,
          status: MemberPaymentStatus.OVERDUE,
          dueDate: new Date('2024-01-03'),
        },
      };

      presenter.present(firstResult);
      presenter.reset();
      presenter.present(secondResult);

      expect(presenter.getResponseModel()).toEqual(secondResult);
    });
  });

  describe('viewModel', () => {
    it('should return the result', () => {
      const result: UpdateMemberPaymentResultDTO = {
        payment: {
          id: 'payment-123',
          feeId: 'fee-123',
          driverId: 'driver-123',
          amount: 100,
          platformFee: 5,
          netAmount: 95,
          status: MemberPaymentStatus.PAID,
          dueDate: new Date('2024-01-01'),
          paidAt: new Date('2024-01-02'),
        },
      };

      presenter.present(result);

      expect(presenter.viewModel).toEqual(result);
    });

    it('should throw error when accessed before present()', () => {
      expect(() => presenter.viewModel).toThrow('Presenter not presented');
    });

    it('should throw error after reset', () => {
      const result: UpdateMemberPaymentResultDTO = {
        payment: {
          id: 'payment-123',
          feeId: 'fee-123',
          driverId: 'driver-123',
          amount: 100,
          platformFee: 5,
          netAmount: 95,
          status: MemberPaymentStatus.PAID,
          dueDate: new Date('2024-01-01'),
          paidAt: new Date('2024-01-02'),
        },
      };

      presenter.present(result);
      presenter.reset();

      expect(() => presenter.viewModel).toThrow('Presenter not presented');
    });
  });
});
