/**
 * Test Script for Bank Reconciliation API
 * Tests all CRUD operations for bank reconciliation
 * Usage: tsx scripts/test-bank-reconciliation.ts
 */

import {
  pgCreateBankReconciliationPeriod,
  pgListBankReconciliationPeriods,
  pgGetBankReconciliationPeriodById,
  pgAddBankTransaction,
  pgGetBankTransactionsForPeriod,
  pgAddLedgerTransaction,
  pgGetLedgerTransactionsForBankAccount,
  pgUpdateLedgerTransactionReconciliationStatus,
  pgCreateReconciliationMatch,
  pgGetReconciliationMatchesForPeriod,
  pgAddBankReconciliationDifference,
  pgGetBankReconciliationDifferencesForPeriod,
} from '../lib/postgres/bank-reconciliation';
import { pgQuery } from '../lib/postgres/client';
import type {
  BankReconciliationPeriod,
  BankTransaction,
  LedgerTransaction,
  ReconciliationMatch,
  BankReconciliationDifference,
} from '../lib/types';

const BANK_ACCOUNT_ID = 'bank-1776171260132-0';
const TEST_USER = 'test@system.local';

async function testBankReconciliation() {
  console.log('🧪 Starting Bank Reconciliation Tests...\n');

  try {
    const cleanupPeriodRows = await pgQuery<{ id: string }>(
      `
      SELECT id
      FROM bank_reconciliation_periods
      WHERE bank_account_id = $1
        AND period_start_date = $2
        AND period_end_date = $3
      `,
      [BANK_ACCOUNT_ID, '2024-01-01', '2024-01-31']
    );

    if (cleanupPeriodRows.rows.length > 0) {
      const periodIds = cleanupPeriodRows.rows.map((r) => r.id);
      await pgQuery('DELETE FROM bank_reconciliation_differences WHERE reconciliation_period_id = ANY($1::TEXT[])', [periodIds]);
      await pgQuery('DELETE FROM reconciliation_matches WHERE reconciliation_period_id = ANY($1::TEXT[])', [periodIds]);
      await pgQuery('DELETE FROM bank_transactions WHERE reconciliation_period_id = ANY($1::TEXT[])', [periodIds]);
      await pgQuery('DELETE FROM ledger_transactions WHERE reconciliation_period_id = ANY($1::TEXT[])', [periodIds]);
      await pgQuery('DELETE FROM bank_reconciliation_periods WHERE id = ANY($1::TEXT[])', [periodIds]);
    }

    // =========================================================================
    // Test 1: Create Reconciliation Period
    // =========================================================================
    console.log('📋 Test 1: Creating Bank Reconciliation Period...');
    const periodData = {
      bankAccountId: BANK_ACCOUNT_ID,
      periodStartDate: '2024-01-01',
      periodEndDate: '2024-01-31',
      statementStartBalance: 100000,
      statementEndBalance: 105000,
      status: 'draft' as const,
      createdBy: TEST_USER,
    };

    const period = await pgCreateBankReconciliationPeriod(
      periodData as Omit<BankReconciliationPeriod, 'id' | 'createdAt' | 'updatedAt'>
    );

    console.log('✅ Period created:');
    console.log(`   ID: ${period.id}`);
    console.log(`   Period: ${period.periodStartDate} to ${period.periodEndDate}`);
    console.log(`   Status: ${period.status}\n`);

    // =========================================================================
    // Test 2: List Reconciliation Periods
    // =========================================================================
    console.log('📋 Test 2: Listing Reconciliation Periods...');
    const periods = await pgListBankReconciliationPeriods(BANK_ACCOUNT_ID, {
      page: 1,
      pageSize: 50,
    });

    console.log(`✅ Found ${periods.total} period(s)`);
    console.log(`   Items in current page: ${periods.items.length}\n`);

    // =========================================================================
    // Test 3: Add Bank Transactions
    // =========================================================================
    console.log('📋 Test 3: Adding Bank Transactions...');
    const bankTxns = [
      {
        reconciliationPeriodId: period.id,
        bankAccountId: BANK_ACCOUNT_ID,
        transactionDate: '2024-01-05',
        amount: 5000,
        direction: 'inward' as const,
        description: 'Customer Payment - INV-001',
        bankReference: 'DEP-001',
        type: 'transfer' as const,
        currencyCode: 'USD',
      },
      {
        reconciliationPeriodId: period.id,
        bankAccountId: BANK_ACCOUNT_ID,
        transactionDate: '2024-01-10',
        amount: 2500,
        direction: 'outward' as const,
        description: 'Check Payment',
        bankReference: 'CHK-1234',
        type: 'check' as const,
        currencyCode: 'USD',
      },
    ];

    const createdBankTxns: BankTransaction[] = [];
    for (const txn of bankTxns) {
      const created = await pgAddBankTransaction(
        txn as Omit<BankTransaction, 'id' | 'createdAt' | 'updatedAt'>
      );
      createdBankTxns.push(created);
      console.log(`✅ Added: ${created.description} (${created.amount})`);
    }
    console.log();

    // =========================================================================
    // Test 4: Retrieve Bank Transactions
    // =========================================================================
    console.log('📋 Test 4: Retrieving Bank Transactions for Period...');
    const retrievedTxns = await pgGetBankTransactionsForPeriod(period.id);
    console.log(`✅ Found ${retrievedTxns.length} transaction(s)`);
    retrievedTxns.forEach((t) => {
      console.log(`   - ${t.description}: ${t.amount} ${t.direction}`);
    });
    console.log();

    // =========================================================================
    // Test 5: Add Ledger Transactions
    // =========================================================================
    console.log('📋 Test 5: Adding Ledger Transactions...');
    const ledgerTxns = [
      {
        bankAccountId: BANK_ACCOUNT_ID,
        journalEntryId: 'je-001',
        journalEntryLineIdx: 0,
        transactionDate: '2024-01-05',
        amount: 5000,
        direction: 'credit' as const,
        description: 'Payment received from customer',
        referenceType: 'invoice',
        referenceId: 'inv-001',
        postingStatus: 'posted' as const,
        reconciliationStatus: 'unreconciled' as const,
        currencyCode: 'USD',
        fxRate: 1.0,
      },
      {
        bankAccountId: BANK_ACCOUNT_ID,
        journalEntryId: 'je-002',
        journalEntryLineIdx: 1,
        transactionDate: '2024-01-10',
        amount: 2500,
        direction: 'debit' as const,
        description: 'Check issued for expense',
        referenceType: 'check',
        referenceId: 'chk-1234',
        postingStatus: 'posted' as const,
        reconciliationStatus: 'unreconciled' as const,
        currencyCode: 'USD',
        fxRate: 1.0,
      },
    ];

    const createdLedgerTxns: LedgerTransaction[] = [];
    for (const txn of ledgerTxns) {
      const created = await pgAddLedgerTransaction(
        txn as Omit<LedgerTransaction, 'id' | 'createdAt' | 'updatedAt'>
      );
      createdLedgerTxns.push(created);
      console.log(`✅ Added: ${created.description}`);
    }
    console.log();

    // =========================================================================
    // Test 6: Get Unreconciled Ledger Transactions
    // =========================================================================
    console.log('📋 Test 6: Retrieving Unreconciled Ledger Transactions...');
    const unreconciledTxns = await pgGetLedgerTransactionsForBankAccount(BANK_ACCOUNT_ID);
    console.log(`✅ Found ${unreconciledTxns.length} unreconciled transaction(s)`);
    unreconciledTxns.forEach((t) => {
      console.log(`   - ${t.description} (${t.reconciliationStatus})`);
    });
    console.log();

    // =========================================================================
    // Test 7: Create Reconciliation Match
    // =========================================================================
    console.log('📋 Test 7: Creating Reconciliation Match...');
    const match = await pgCreateReconciliationMatch({
      reconciliationPeriodId: period.id,
      bankTransactionId: createdBankTxns[0].id,
      ledgerTransactionIds: [createdLedgerTxns[0].id],
      matchType: 'auto',
      matchConfidence: 95,
      matchDate: new Date().toISOString(),
      matchedBy: TEST_USER,
      notes: 'Automatic match based on amount and date',
      status: 'matched',
    } as Omit<ReconciliationMatch, 'id' | 'createdAt' | 'updatedAt'>);

    console.log('✅ Match created:');
    console.log(`   ID: ${match.id}`);
    console.log(`   Confidence: ${match.matchConfidence}%\n`);

    // =========================================================================
    // Test 8: List Reconciliation Matches
    // =========================================================================
    console.log('📋 Test 8: Listing Reconciliation Matches...');
    const matches = await pgGetReconciliationMatchesForPeriod(period.id);
    console.log(`✅ Found ${matches.length} match(es)\n`);

    // =========================================================================
    // Test 9: Update Ledger Transaction Status
    // =========================================================================
    console.log('📋 Test 9: Updating Ledger Transaction Status...');
    const statusUpdated = await pgUpdateLedgerTransactionReconciliationStatus(
      createdLedgerTxns[0].id,
      'reconciled',
      period.id
    );

    if (statusUpdated) {
      console.log(`✅ Transaction status updated to: reconciled\n`);
    } else {
      console.log(`❌ Failed to update transaction status\n`);
    }

    // =========================================================================
    // Test 10: Add Reconciliation Difference
    // =========================================================================
    console.log('📋 Test 10: Adding Reconciliation Difference...');
    const difference = await pgAddBankReconciliationDifference({
      reconciliationPeriodId: period.id,
      type: 'outstanding_check',
      amount: 1500,
      description: 'Check #5678 not yet cleared',
      ledgerTransactionId: createdLedgerTxns[1].id,
      resolutionType: 'pending',
    } as Omit<BankReconciliationDifference, 'id' | 'createdAt' | 'updatedAt'>);

    console.log('✅ Difference created:');
    console.log(`   Type: ${difference.type}`);
    console.log(`   Amount: ${difference.amount}\n`);

    // =========================================================================
    // Test 11: List Differences
    // =========================================================================
    console.log('📋 Test 11: Listing Reconciliation Differences...');
    const differences = await pgGetBankReconciliationDifferencesForPeriod(period.id);
    console.log(`✅ Found ${differences.length} difference(s)\n`);

    // =========================================================================
    // Summary
    // =========================================================================
    console.log('✅ All tests completed successfully!');
    console.log('\n📊 Summary:');
    console.log(`   - Created reconciliation period: ${period.id}`);
    console.log(`   - Added ${createdBankTxns.length} bank transactions`);
    console.log(`   - Added ${createdLedgerTxns.length} ledger transactions`);
    console.log(`   - Created ${matches.length} reconciliation match(es)`);
    console.log(`   - Added ${differences.length} difference(s)`);
    console.log('\n🎯 Next: Implement auto-matching algorithm and UI components');

    process.exit(0);
  } catch (error) {
    console.error('\n❌ Test failed:');
    console.error(error instanceof Error ? error.message : error);
    process.exit(1);
  }
}

testBankReconciliation();
