import { LedgerEntry } from './ledger-entry.aggregate';
import { UserId, LedgerEntryType, Money } from '@/domain/value-objects';
import Decimal from 'decimal.js';

jest.mock('@/shared/exceptions/domain.exception', () => ({
  DomainError: class DomainError extends Error {
    constructor(message: string) {
      super(message);
      this.name = 'DomainError';
    }
  },
}));

describe('LedgerEntry Aggregate', () => {
  describe('create', () => {
    it('should create a new ledger entry', () => {
      const entry = LedgerEntry.create({
        accountSequence: 'D2512110001',
        userId: UserId.create(1),
        entryType: LedgerEntryType.DEPOSIT_KAVA,
        amount: Money.USDT(100),
        balanceAfter: Money.USDT(100),
        refTxHash: 'tx_hash_123',
        memo: 'Test deposit',
      });

      expect(entry.entryType).toBe(LedgerEntryType.DEPOSIT_KAVA);
      expect(entry.amount.value).toBe(100);
      expect(entry.assetType).toBe('USDT');
      expect(entry.balanceAfter?.value).toBe(100);
      expect(entry.refTxHash).toBe('tx_hash_123');
      expect(entry.memo).toBe('Test deposit');
    });

    it('should create entry with optional fields as null', () => {
      const entry = LedgerEntry.create({
        accountSequence: 'D2512110001',
        userId: UserId.create(1),
        entryType: LedgerEntryType.PLANT_PAYMENT,
        amount: Money.signed(-50, 'USDT'),
      });

      expect(entry.balanceAfter).toBeNull();
      expect(entry.refOrderId).toBeNull();
      expect(entry.refTxHash).toBeNull();
      expect(entry.memo).toBeNull();
      expect(entry.payloadJson).toBeNull();
    });

    it('should create entry with payload json', () => {
      const payload = { key: 'value', number: 123 };
      const entry = LedgerEntry.create({
        accountSequence: 'D2512110001',
        userId: UserId.create(1),
        entryType: LedgerEntryType.REWARD_PENDING,
        amount: Money.USDT(10),
        payloadJson: payload,
      });

      expect(entry.payloadJson).toEqual(payload);
    });
  });

  describe('reconstruct', () => {
    it('should reconstruct ledger entry from database record', () => {
      const entry = LedgerEntry.reconstruct({
        id: BigInt(1),
        accountSequence: 'D2512110100',
        userId: BigInt(100),
        entryType: 'DEPOSIT_KAVA',
        amount: new Decimal(50),
        assetType: 'USDT',
        balanceAfter: new Decimal(150),
        refOrderId: 'order_123',
        refTxHash: 'tx_123',
        memo: 'Reconstructed entry',
        payloadJson: { test: true },
        createdAt: new Date('2024-01-01'),
      });

      expect(entry.id).toBe(BigInt(1));
      expect(entry.userId.value).toBe(BigInt(100));
      expect(entry.entryType).toBe('DEPOSIT_KAVA');
      expect(entry.amount.value).toBe(50);
      expect(entry.balanceAfter?.value).toBe(150);
    });
  });
});
