"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processTransfer = processTransfer;
const uuid_1 = require("uuid");
const settlement_core_1 = require("@dbis/settlement-core");
const config_1 = require("../config");
const fineract_1 = require("../adapters/fineract");
const hybx_production_1 = require("../adapters/hybx-production");
const omnl_1 = require("../adapters/omnl");
const swift_1 = require("../adapters/swift");
const settlement_store_1 = require("../store/settlement-store");
async function processTransfer(input) {
    const cfg = (0, config_1.loadConfig)();
    const profile = (0, config_1.loadOfficeProfile)();
    const officeId = (0, config_1.settlementOfficeId)(input.officeId);
    const req = { ...input, officeId };
    const isExternal = req.rail === 'SWIFT' || req.rail === 'RTGS';
    const existing = settlement_store_1.settlementStore.getByIdempotencyKey(req.idempotencyKey);
    if (existing?.phase === 'SETTLED')
        return existing;
    const now = new Date().toISOString();
    let record = existing ?? {
        settlementId: (0, uuid_1.v4)(),
        idempotencyKey: req.idempotencyKey,
        phase: 'RECEIVED',
        request: {
            idempotencyKey: req.idempotencyKey,
            officeId,
            valueDate: now.slice(0, 10),
            currency: req.currency ?? 'USD',
            amount: req.amount,
            creditorIban: req.creditorIban ?? (isExternal ? '' : 'INTERNAL-CHAIN138'),
            beneficiaryName: req.beneficiaryName ?? req.recipientAddress,
            remittanceInfo: req.remittanceInfo ?? `Transfer ${req.tokenSymbol} → ${req.recipientAddress}`,
            moneyLayers: req.moneyLayers.length ? req.moneyLayers : ['M2'],
            rail: req.rail === 'CHAIN138' ? 'CHAIN138' : req.rail === 'INTERNAL' ? 'INTERNAL' : 'SWIFT',
        },
        errors: [],
        createdAt: now,
        updatedAt: now,
    };
    const advance = (phase, patch = {}) => {
        record = { ...record, phase, updatedAt: new Date().toISOString(), ...patch };
        settlement_store_1.settlementStore.save(record);
    };
    try {
        if (isExternal && !req.creditorIban) {
            throw new Error('creditorIban required for external transfer');
        }
        advance('VALIDATED');
        advance('VERBIAGE_ROLLED', {
            verbiageDocument: [
                `OMNL ${req.rail} transfer · ${req.tokenSymbol}`,
                `M2 layer · ${req.amount}`,
                `To ${req.recipientAddress}`,
                isExternal ? `IBAN ${req.creditorIban}` : 'Internal / Chain 138',
            ].join('\n'),
        });
        const amount = parseFloat(req.amount) || 0;
        if (amount > 0) {
            const [debitGlId, creditGlId] = await Promise.all([
                (0, fineract_1.resolveGlAccountId)(profile.settlement.glM2 ?? settlement_core_1.GL_CODES.M2_BROAD),
                (0, fineract_1.resolveGlAccountId)(profile.settlement.glSettlement ?? settlement_core_1.GL_CODES.SETTLEMENT_SUSPENSE),
            ]);
            const je = await (0, fineract_1.postJournalEntry)({
                officeId,
                transactionDate: now.slice(0, 10),
                referenceNumber: req.idempotencyKey,
                comments: `${req.rail} transfer ${req.tokenSymbol}`,
                debits: [{ glAccountId: debitGlId, amount }],
                credits: [{ glAccountId: creditGlId, amount }],
            });
            advance('FINERACT_POSTED', { fineractJournalRef: String(je.resourceId) });
        }
        else {
            advance('FINERACT_POSTED');
        }
        if (isExternal && cfg.rails.hybx.enabled) {
            const hybx = new hybx_production_1.HybxProductionRail();
            const pay = await hybx.dispatchPayment({
                idempotencyKey: req.idempotencyKey,
                amount: req.amount,
                currency: req.currency ?? 'USD',
                creditorIban: req.creditorIban,
                beneficiaryName: req.beneficiaryName ?? req.recipientAddress,
                remittanceInfo: req.remittanceInfo ?? `OMNL ${req.tokenSymbol} external transfer`,
                rail: req.rail === 'RTGS' ? 'RTGS' : 'SWIFT',
            });
            advance('HYBX_RAIL_DISPATCHED', { hybxPaymentId: pay.paymentId });
        }
        else {
            advance('HYBX_RAIL_DISPATCHED');
        }
        if (isExternal && cfg.rails.swift.enabled && req.creditorIban) {
            const swiftRaw = (0, swift_1.buildMt103Stub)({
                senderRef: req.idempotencyKey,
                currency: req.currency ?? 'USD',
                amount: req.amount,
                valueDate: now.slice(0, 10),
                orderingCustomer: cfg.omnlLegalName,
                beneficiary: req.beneficiaryName ?? req.recipientAddress,
                iban: req.creditorIban,
                remittance: req.remittanceInfo ?? `OMNL ${req.tokenSymbol}`,
            });
            await (0, swift_1.forwardSwiftToListener)(swiftRaw);
            const iso = await (0, omnl_1.archiveIso20022)({
                messageType: 'pacs.008',
                direction: 'OUTBOUND',
                raw: swiftRaw,
                settlementRef: record.settlementId,
            });
            advance('ISO20022_ARCHIVED', { iso20022MessageId: iso.messageId });
        }
        else {
            advance('ISO20022_ARCHIVED');
        }
        if (!isExternal && req.tokenAddress && cfg.production.allowChainMintExecute) {
            const xfer = await (0, omnl_1.requestTokenTransfer)({
                tokenAddress: req.tokenAddress,
                amount: req.amount,
                recipient: req.recipientAddress,
                settlementRef: record.settlementId,
                dryRun: false,
                symbol: req.tokenSymbol,
            });
            advance('CHAIN_MINT_REQUESTED', {
                chainTxHash: xfer.txHash,
                verbiageDocument: [
                    record.verbiageDocument,
                    `On-chain ERC-20 transfer: ${req.tokenAddress} → ${req.recipientAddress}`,
                    xfer.txHash ? `tx ${xfer.txHash}` : `status ${xfer.status}`,
                ].join('\n'),
            });
        }
        else {
            advance('CHAIN_MINT_REQUESTED', {
                verbiageDocument: [
                    record.verbiageDocument,
                    isExternal
                        ? 'Bank rail (SWIFT/IBAN) — no on-chain transfer'
                        : `On-chain ERC-20 transfer prepared: ${req.tokenAddress} → ${req.recipientAddress}`,
                ].join('\n'),
            });
        }
        advance('SETTLED');
        return record;
    }
    catch (err) {
        record.errors.push(err instanceof Error ? err.message : String(err));
        advance('FAILED');
        return record;
    }
}
