import { describe, expect, it } from 'vitest';
import { Money } from '../../value-objects/Money';
import { LeagueWalletId } from './LeagueWalletId';
import { Transaction } from './Transaction';
import { TransactionId } from './TransactionId';

describe('Transaction', () => {
  const validId = TransactionId.create('tx1');
  const validWalletId = LeagueWalletId.create('wallet1');
  const validAmount = Money.create(10000, 'USD'); // $100.00

  const validProps = {
    id: validId,
    walletId: validWalletId,
    type: 'sponsorship_payment' as const,
    amount: validAmount,
    completedAt: undefined,
    description: 'Test transaction',
    metadata: undefined,
  };

  describe('create', () => {
    it('should create a transaction with default values', () => {
      const transaction = Transaction.create(validProps);

      expect(transaction.id).toBe(validId);
      expect(transaction.walletId).toBe(validWalletId);
      expect(transaction.type).toBe('sponsorship_payment');
      expect(transaction.amount).toBe(validAmount);
      expect(transaction.status).toBe('pending');
      expect(transaction.createdAt).toBeInstanceOf(Date);
      expect(transaction.completedAt).toBeUndefined();
      expect(transaction.description).toBe('Test transaction');
      expect(transaction.platformFee.amount).toBe(1000); // 10% of 10000
      expect(transaction.netAmount.amount).toBe(9000); // 10000 - 1000
    });

    it('should create a transaction with custom createdAt and status', () => {
      const customDate = new Date('2023-01-01');
      const transaction = Transaction.create({
        ...validProps,
        createdAt: customDate,
        status: 'completed',
      });

      expect(transaction.createdAt).toBe(customDate);
      expect(transaction.status).toBe('completed');
    });


    it('should throw on zero amount', () => {
      const zeroAmount = Money.create(0, 'USD');
      expect(() => Transaction.create({ ...validProps, amount: zeroAmount })).toThrow('Transaction amount must be greater than zero');
    });

    it('should throw on negative amount', () => {
      expect(() => Money.create(-100, 'USD')).toThrow();
    });
  });

  describe('complete', () => {
    it('should complete a pending transaction', () => {
      const transaction = Transaction.create(validProps);
      const completed = transaction.complete();

      expect(completed.status).toBe('completed');
      expect(completed.completedAt).toBeInstanceOf(Date);
    });

    it('should throw on completing already completed transaction', () => {
      const transaction = Transaction.create({ ...validProps, status: 'completed' });
      expect(() => transaction.complete()).toThrow('Transaction is already completed');
    });

    it('should throw on completing failed transaction', () => {
      const transaction = Transaction.create({ ...validProps, status: 'failed' });
      expect(() => transaction.complete()).toThrow('Cannot complete a failed or cancelled transaction');
    });

    it('should throw on completing cancelled transaction', () => {
      const transaction = Transaction.create({ ...validProps, status: 'cancelled' });
      expect(() => transaction.complete()).toThrow('Cannot complete a failed or cancelled transaction');
    });
  });

  describe('fail', () => {
    it('should fail a pending transaction', () => {
      const transaction = Transaction.create(validProps);
      const failed = transaction.fail();

      expect(failed.status).toBe('failed');
    });

    it('should throw on failing completed transaction', () => {
      const transaction = Transaction.create({ ...validProps, status: 'completed' });
      expect(() => transaction.fail()).toThrow('Cannot fail a completed transaction');
    });
  });

  describe('cancel', () => {
    it('should cancel a pending transaction', () => {
      const transaction = Transaction.create(validProps);
      const cancelled = transaction.cancel();

      expect(cancelled.status).toBe('cancelled');
    });

    it('should throw on cancelling completed transaction', () => {
      const transaction = Transaction.create({ ...validProps, status: 'completed' });
      expect(() => transaction.cancel()).toThrow('Cannot cancel a completed transaction');
    });
  });

  describe('isCompleted', () => {
    it('should return true for completed transaction', () => {
      const transaction = Transaction.create({ ...validProps, status: 'completed' });
      expect(transaction.isCompleted()).toBe(true);
    });

    it('should return false for non-completed transaction', () => {
      const transaction = Transaction.create(validProps);
      expect(transaction.isCompleted()).toBe(false);
    });
  });

  describe('isPending', () => {
    it('should return true for pending transaction', () => {
      const transaction = Transaction.create(validProps);
      expect(transaction.isPending()).toBe(true);
    });

    it('should return false for non-pending transaction', () => {
      const transaction = Transaction.create({ ...validProps, status: 'completed' });
      expect(transaction.isPending()).toBe(false);
    });
  });
});