import { pgQuery } from '../lib/postgres/client';
import {
  pgCreateBankReconciliationPeriod,
  pgBatchAddBankTransactions,
  pgAddLedgerTransaction,
  pgGetReconciliationMatchesForPeriod,
} from '../lib/postgres/bank-reconciliation';
import { dryRunApplyAutoMatchFromPreviewForPeriod } from '../lib/services/bank-reconciliation-auto-match';
import type {
  BankReconciliationPeriod,
  BankTransaction,
  LedgerTransaction,
} from '../lib/types';

const BANK_ACCOUNT_ID = 'bank-1776171260132-0';

async function main() {
  try {
    const periodStart = '2024-04-01';
    const periodEnd = '2024-04-30';

    const cleanupRows = 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, periodStart, periodEnd]
    );

    if (cleanupRows.rows.length > 0) {
      const ids = cleanupRows.rows.map((r) => r.id);
      const ledgerRows = await pgQuery<{ id: string }>(
        'SELECT id FROM ledger_transactions WHERE reconciliation_period_id = ANY($1::TEXT[])',
        [ids]
      );
      const ledgerIds = ledgerRows.rows.map((r) => r.id);
      if (ledgerIds.length > 0) {
        await pgQuery(
          'DELETE FROM bank_reconciliation_differences WHERE ledger_transaction_id = ANY($1::TEXT[])',
          [ledgerIds]
        );
      }
      await pgQuery('DELETE FROM bank_reconciliation_differences WHERE reconciliation_period_id = ANY($1::TEXT[])', [ids]);
      await pgQuery('DELETE FROM reconciliation_matches WHERE reconciliation_period_id = ANY($1::TEXT[])', [ids]);
      await pgQuery('DELETE FROM bank_transactions WHERE reconciliation_period_id = ANY($1::TEXT[])', [ids]);
      await pgQuery('DELETE FROM ledger_transactions WHERE reconciliation_period_id = ANY($1::TEXT[])', [ids]);
      await pgQuery('DELETE FROM bank_reconciliation_periods WHERE id = ANY($1::TEXT[])', [ids]);
    }

    const period = await pgCreateBankReconciliationPeriod({
      bankAccountId: BANK_ACCOUNT_ID,
      periodStartDate: periodStart,
      periodEndDate: periodEnd,
      statementStartBalance: 80000,
      statementEndBalance: 83000,
      status: 'draft',
      createdBy: 'dryrun@system.local',
    } as Omit<BankReconciliationPeriod, 'id' | 'createdAt' | 'updatedAt'>);

    await pgBatchAddBankTransactions([
      {
        reconciliationPeriodId: period.id,
        bankAccountId: BANK_ACCOUNT_ID,
        transactionDate: '2024-04-07',
        amount: 3000,
        direction: 'inward',
        description: 'Receipt DRY-01',
        bankReference: 'DRY-01',
        type: 'transfer',
        currencyCode: 'USD',
      },
    ] as Omit<BankTransaction, 'id' | 'createdAt' | 'updatedAt'>[]);

    await pgAddLedgerTransaction({
      bankAccountId: BANK_ACCOUNT_ID,
      journalEntryId: 'je-dry-1',
      journalEntryLineIdx: 0,
      transactionDate: '2024-04-07',
      amount: 3000,
      direction: 'inward',
      description: 'Receipt DRY-01',
      referenceType: 'invoice',
      referenceId: 'dry-01',
      postingStatus: 'posted',
      reconciliationStatus: 'unreconciled',
      currencyCode: 'USD',
      fxRate: 1,
    } as Omit<LedgerTransaction, 'id' | 'createdAt' | 'updatedAt'>);

    const beforeMatches = await pgGetReconciliationMatchesForPeriod(period.id);
    const dryRun = await dryRunApplyAutoMatchFromPreviewForPeriod(period.id, 80);
    const afterMatches = await pgGetReconciliationMatchesForPeriod(period.id);

    console.log(`DryRun appliedCount: ${dryRun.appliedCount}`);
    console.log(`DryRun skippedCount: ${dryRun.skippedCount}`);
    console.log(`Matches before: ${beforeMatches.length}`);
    console.log(`Matches after: ${afterMatches.length}`);

    if (dryRun.appliedCount < 1) {
      throw new Error('Expected at least one candidate in dry run');
    }

    if (beforeMatches.length !== afterMatches.length) {
      throw new Error('Dry run must not persist matches');
    }

    console.log('Dry run flow test passed');
    process.exit(0);
  } catch (error) {
    console.error(error instanceof Error ? error.message : error);
    process.exit(1);
  }
}

main();
