// Oracle Banking Platform Adapter
// Maps Oracle Banking Platform internal schemas to DBIS Nostro/Vostro API

import { BasePluginAdapter } from './generic-adapter';
import {
  ParticipantCreateRequest,
  AccountCreateRequest,
  TransferCreateRequest,
  NostroVostroTransfer,
  NostroVostroAccount,
  AccountType,
} from '@/core/nostro-vostro/nostro-vostro.types';

interface OracleBankingParty {
  partyId: string;
  partyName: string;
  bic?: string;
  lei?: string;
  countryCode: string;
  partyType: string; // BANK, CENTRAL_BANK, etc.
}

interface OracleBankingAccount {
  accountId: string;
  partyId: string;
  accountNumber: string;
  currencyCode: string;
  accountCategory: string; // NOSTRO, VOSTRO
  ledgerBalance: number;
  availableBalance: number;
  holdBalance: number;
  accountStatus: string;
}

interface OracleBankingTransaction {
  transactionId: string;
  debitAccountId: string;
  creditAccountId: string;
  amount: number;
  currencyCode: string;
  valueDate: string;
  transactionDescription: string;
  transactionCode: string;
}

export class OracleBankingAdapter extends BasePluginAdapter {
  private oracleEndpoint?: string;
  private oracleUser?: string;
  private oraclePassword?: string;

  constructor(config: Record<string, unknown> = {}) {
    super('Oracle Banking Platform', '1.0.0', config);
    this.oracleEndpoint = config.oracleEndpoint as string;
    this.oracleUser = config.oracleUser as string;
    this.oraclePassword = config.oraclePassword as string;
  }

  async isAvailable(): Promise<boolean> {
    if (!this.oracleEndpoint) {
      return false;
    }

    try {
      // In production, check Oracle Banking Platform API
      return true; // Mock for now
    } catch {
      return false;
    }
  }

  mapParticipant(internalData: unknown): ParticipantCreateRequest {
    const party = internalData as OracleBankingParty;

    const regulatoryTierMap: Record<string, string> = {
      CENTRAL_BANK: 'SCB',
      BANK: 'Tier1',
      FINANCIAL_INSTITUTION: 'Tier2',
      PAYMENT_PROVIDER: 'PSP',
    };

    return {
      participantId: party.partyId,
      name: party.partyName,
      bic: party.bic,
      lei: party.lei,
      country: party.countryCode,
      regulatoryTier: regulatoryTierMap[party.partyType] || 'Tier2',
      metadata: {
        oraclePartyId: party.partyId,
        oraclePartyType: party.partyType,
      },
    };
  }

  mapAccount(internalData: unknown): AccountCreateRequest {
    const account = internalData as OracleBankingAccount;

    return {
      ownerParticipantId: account.partyId,
      counterpartyParticipantId: account.partyId,
      ibanOrLocalAccount: account.accountNumber,
      currency: account.currencyCode,
      accountType: account.accountCategory === 'NOSTRO' ? AccountType.NOSTRO : AccountType.VOSTRO,
      metadata: {
        oracleAccountId: account.accountId,
        oracleAccountNumber: account.accountNumber,
      },
    };
  }

  mapTransfer(internalData: unknown): TransferCreateRequest {
    const transaction = internalData as OracleBankingTransaction;

    return {
      fromAccountId: transaction.debitAccountId,
      toAccountId: transaction.creditAccountId,
      amount: transaction.amount.toString(),
      currency: transaction.currencyCode,
      valueDate: transaction.valueDate,
      reference: transaction.transactionDescription,
      metadata: {
        oracleTransactionId: transaction.transactionId,
        oracleTransactionCode: transaction.transactionCode,
      },
    };
  }

  mapTransferToInternal(transfer: NostroVostroTransfer): unknown {
    return {
      transactionId: transfer.transferId,
      debitAccountId: transfer.fromAccountId,
      creditAccountId: transfer.toAccountId,
      amount: parseFloat(transfer.amount),
      currencyCode: transfer.currency,
      valueDate: transfer.valueDate.toISOString().split('T')[0],
      transactionDescription: transfer.reference || `DBIS Transfer ${transfer.transferId}`,
      transactionCode: 'FT',
      metadata: {
        dbisTransferId: transfer.transferId,
        settlementAsset: transfer.settlementAsset,
      },
    };
  }

  mapAccountToInternal(account: NostroVostroAccount): unknown {
    return {
      accountId: account.accountId,
      accountNumber: account.ibanOrLocalAccount,
      currencyCode: account.currency,
      accountCategory: account.accountType,
      ledgerBalance: parseFloat(account.currentBalance),
      availableBalance: parseFloat(account.availableLiquidity),
      holdBalance: parseFloat(account.holdAmount),
      accountStatus: account.status,
    };
  }

  async postTransfer(transfer: NostroVostroTransfer): Promise<{ success: boolean; internalId?: string; error?: string }> {
    try {
      const oracleTransaction = this.mapTransferToInternal(transfer);

      // In production, call Oracle Banking Platform API
      const internalId = this.generateInternalReference('OBP');
      return { success: true, internalId };
    } catch (error) {
      return this.handleError(error, 'postTransfer');
    }
  }

  async getAccountBalance(accountId: string): Promise<{ balance: string; available: string; hold: string }> {
    try {
      return {
        balance: '0',
        available: '0',
        hold: '0',
      };
    } catch (error) {
      throw new Error(`Failed to get balance: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }

  async reconcile(accountId: string, asOfDate: Date): Promise<{ matched: number; breaks: unknown[] }> {
    try {
      return {
        matched: 0,
        breaks: [],
      };
    } catch (error) {
      throw new Error(`Reconciliation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }
}
