// Ledger Service Unit Tests

import { ledgerService } from '@/core/ledger/ledger.service';
import { createTestSovereignBank, createTestBankAccount, cleanDatabase } from '@/__tests__/utils/test-db';
import { testPrisma } from '@/__tests__/utils/test-db';
import { Decimal } from '@prisma/client/runtime/library';

describe('LedgerService', () => {
  beforeEach(async () => {
    await cleanDatabase();
  });

  afterAll(async () => {
    await testPrisma.$disconnect();
  });

  describe('postEntry', () => {
    it('should create a double-entry ledger entry', async () => {
      const bank = await createTestSovereignBank();
      const debitAccount = await createTestBankAccount({
        sovereignBankId: bank.id,
        accountNumber: 'DEBIT-001',
        balance: '1000.00',
      });
      const creditAccount = await createTestBankAccount({
        sovereignBankId: bank.id,
        accountNumber: 'CREDIT-001',
        balance: '500.00',
      });

      const result = await ledgerService.postEntry({
        ledgerId: 'MASTER',
        debitAccountId: debitAccount.id,
        creditAccountId: creditAccount.id,
        amount: '100.00',
        currencyCode: 'USD',
        assetType: 'fiat',
        transactionType: 'TYPE_A',
        referenceId: 'TEST-REF-001',
      });

      expect(result.status).toBe('posted');
      expect(result.entryIds).toHaveLength(1);

      // Verify balances updated
      const updatedDebit = await testPrisma.bankAccount.findUnique({
        where: { id: debitAccount.id },
      });
      const updatedCredit = await testPrisma.bankAccount.findUnique({
        where: { id: creditAccount.id },
      });

      expect(updatedDebit?.balance.toString()).toBe('900.00');
      expect(updatedCredit?.balance.toString()).toBe('600.00');
    });

    it('should validate debits equal credits', async () => {
      const bank = await createTestSovereignBank();
      const debitAccount = await createTestBankAccount({
        sovereignBankId: bank.id,
      });
      const creditAccount = await createTestBankAccount({
        sovereignBankId: bank.id,
      });

      await expect(
        ledgerService.postEntry({
          ledgerId: 'MASTER',
          debitAccountId: debitAccount.id,
          creditAccountId: creditAccount.id,
          amount: '100.00',
          currencyCode: 'USD',
          assetType: 'fiat',
          transactionType: 'TYPE_A',
          referenceId: 'TEST-REF-002',
        })
      ).resolves.toBeDefined();
    });

    it('should reject entry if debit account has insufficient balance', async () => {
      const bank = await createTestSovereignBank();
      const debitAccount = await createTestBankAccount({
        sovereignBankId: bank.id,
        balance: '50.00',
      });
      const creditAccount = await createTestBankAccount({
        sovereignBankId: bank.id,
      });

      await expect(
        ledgerService.postEntry({
          ledgerId: 'MASTER',
          debitAccountId: debitAccount.id,
          creditAccountId: creditAccount.id,
          amount: '100.00',
          currencyCode: 'USD',
          assetType: 'fiat',
          transactionType: 'TYPE_A',
          referenceId: 'TEST-REF-003',
        })
      ).rejects.toThrow();
    });
  });

  describe('hashChaining', () => {
    it('should chain ledger entries with previous hash', async () => {
      const bank = await createTestSovereignBank();
      const debitAccount = await createTestBankAccount({
        sovereignBankId: bank.id,
      });
      const creditAccount = await createTestBankAccount({
        sovereignBankId: bank.id,
      });

      const entry1 = await ledgerService.postEntry({
        ledgerId: 'MASTER',
        debitAccountId: debitAccount.id,
        creditAccountId: creditAccount.id,
        amount: '100.00',
        currencyCode: 'USD',
        assetType: 'fiat',
        transactionType: 'TYPE_A',
        referenceId: 'TEST-REF-004',
      });

      const entry2 = await ledgerService.postEntry({
        ledgerId: 'MASTER',
        debitAccountId: debitAccount.id,
        creditAccountId: creditAccount.id,
        amount: '50.00',
        currencyCode: 'USD',
        assetType: 'fiat',
        transactionType: 'TYPE_A',
        referenceId: 'TEST-REF-005',
      });

      const ledgerEntry1 = await testPrisma.ledgerEntry.findUnique({
        where: { id: entry1.entryIds[0] },
      });
      const ledgerEntry2 = await testPrisma.ledgerEntry.findUnique({
        where: { id: entry2.entryIds[0] },
      });

      expect(ledgerEntry2?.previousHash).toBe(ledgerEntry1?.blockHash);
    });
  });
});

