// SAP Banking Adapter
// Maps SAP Banking Services 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 SAPBankingBusinessPartner {
  businessPartner: string;
  businessPartnerName: string;
  bic?: string;
  lei?: string;
  country: string;
  businessPartnerCategory: string; // BANK, CENTRAL_BANK, etc.
}

interface SAPBankingAccount {
  accountId: string;
  businessPartner: string;
  accountNumber: string;
  currency: string;
  accountType: string; // NOSTRO, VOSTRO
  balance: number;
  availableBalance: number;
  blockedAmount: number;
  accountStatus: string;
}

interface SAPBankingTransaction {
  transactionId: string;
  debitAccount: string;
  creditAccount: string;
  amount: number;
  currency: string;
  valueDate: string;
  transactionText: string;
  transactionType: string;
}

export class SAPBankingAdapter extends BasePluginAdapter {
  private sapEndpoint?: string;
  private sapClient?: string;
  private sapUser?: string;
  private sapPassword?: string;

  constructor(config: Record<string, unknown> = {}) {
    super('SAP Banking', '1.0.0', config);
    this.sapEndpoint = config.sapEndpoint as string;
    this.sapClient = config.sapClient as string;
    this.sapUser = config.sapUser as string;
    this.sapPassword = config.sapPassword as string;
  }

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

    try {
      // In production, check SAP RFC connection or OData service
      // const response = await fetch(`${this.sapEndpoint}/sap/bc/health`, {
      //   headers: { 'Authorization': `Basic ${btoa(`${this.sapUser}:${this.sapPassword}`)}` }
      // });
      // return response.ok;
      return true; // Mock for now
    } catch {
      return false;
    }
  }

  mapParticipant(internalData: unknown): ParticipantCreateRequest {
    const bp = internalData as SAPBankingBusinessPartner;

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

    return {
      participantId: bp.businessPartner,
      name: bp.businessPartnerName,
      bic: bp.bic,
      lei: bp.lei,
      country: bp.country,
      regulatoryTier: regulatoryTierMap[bp.businessPartnerCategory] || 'Tier2',
      metadata: {
        sapBusinessPartner: bp.businessPartner,
        sapCategory: bp.businessPartnerCategory,
      },
    };
  }

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

    return {
      ownerParticipantId: account.businessPartner,
      counterpartyParticipantId: account.businessPartner,
      ibanOrLocalAccount: account.accountNumber,
      currency: account.currency,
      accountType: account.accountType === 'NOSTRO' ? AccountType.NOSTRO : AccountType.VOSTRO,
      metadata: {
        sapAccountId: account.accountId,
        sapAccountNumber: account.accountNumber,
      },
    };
  }

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

    return {
      fromAccountId: transaction.debitAccount,
      toAccountId: transaction.creditAccount,
      amount: transaction.amount.toString(),
      currency: transaction.currency,
      valueDate: transaction.valueDate,
      reference: transaction.transactionText,
      metadata: {
        sapTransactionId: transaction.transactionId,
        sapTransactionType: transaction.transactionType,
      },
    };
  }

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

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

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

      // In production, call SAP RFC function or OData service
      // const response = await fetch(`${this.sapEndpoint}/sap/bc/odata/...`, {
      //   method: 'POST',
      //   headers: {
      //     'Authorization': `Basic ${btoa(`${this.sapUser}:${this.sapPassword}`)}`,
      //     'Content-Type': 'application/json'
      //   },
      //   body: JSON.stringify(sapTransaction)
      // });

      const internalId = this.generateInternalReference('SAP');
      return { success: true, internalId };
    } catch (error) {
      return this.handleError(error, 'postTransfer');
    }
  }

  async getAccountBalance(accountId: string): Promise<{ balance: string; available: string; hold: string }> {
    try {
      // In production, query SAP Banking Services
      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'}`);
    }
  }
}
