"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseSwiftFin = parseSwiftFin;
exports.detectInboundFormat = detectInboundFormat;
exports.parseIso20022 = parseIso20022;
exports.parseJsonBroadcast = parseJsonBroadcast;
exports.parseInbound = parseInbound;
exports.parseKtt = parseKtt;
function parseSwiftFields(text) {
    const fields = {};
    let currentField = null;
    let currentValue = [];
    for (const line of text.split('\n')) {
        const m = line.match(/^:(\d{2}[A-Z]?):(.*)$/);
        if (m) {
            if (currentField)
                fields[currentField] = currentValue.join('\n').trim();
            currentField = m[1];
            currentValue = [m[2] ?? ''];
        }
        else if (currentField) {
            currentValue.push(line);
        }
    }
    if (currentField)
        fields[currentField] = currentValue.join('\n').trim();
    return fields;
}
function extractBraceBlocks(raw) {
    const blocks = new Map();
    const b2 = raw.match(/\{2:([^}]*)\}/);
    if (b2)
        blocks.set(2, b2[1].trim());
    const b4 = raw.match(/\{4:([\s\S]*?)-\}/);
    if (b4)
        blocks.set(4, b4[1].trim());
    return blocks;
}
function parseBlock(lines, blockNum, braceBlocks) {
    if (braceBlocks?.has(blockNum))
        return braceBlocks.get(blockNum);
    const blockStart = `${blockNum}:`;
    const blockEnd = `-${blockNum}`;
    const out = [];
    let inBlock = false;
    for (const line of lines) {
        if (line.startsWith(blockStart)) {
            inBlock = true;
            out.push(line.slice(blockStart.length));
            continue;
        }
        if (line.startsWith(blockEnd))
            break;
        if (inBlock)
            out.push(line);
    }
    return out.join('\n');
}
function parseTextBlock(lines, braceBlocks) {
    if (braceBlocks?.has(4)) {
        const text = braceBlocks.get(4);
        return text.startsWith(':') ? text : `:${text}`;
    }
    const out = [];
    let inText = false;
    for (const line of lines) {
        if (line.startsWith('4:')) {
            inText = true;
            out.push(line.slice(2));
            continue;
        }
        if (line.startsWith('-') && !line.startsWith('-4'))
            break;
        if (inText)
            out.push(line);
    }
    return out.join('\n');
}
function extractMessageType(appHeader) {
    const mt = appHeader.match(/MT(\d{3})/);
    if (mt)
        return `MT${mt[1]}`;
    const io = appHeader.match(/[IO](\d{3})/);
    if (io)
        return `MT${io[1]}`;
    return 'UNKNOWN';
}
function split32A(v) {
    const parts = v.trim().split(/\s+/);
    return {
        valueDate: parts[0] ?? '',
        currency: parts[1] ?? '',
        amount: parts[2] ?? '',
    };
}
function parseMt103(fields) {
    const amt = split32A(fields['32A'] ?? '');
    return {
        senderReference: fields['20'] ?? '',
        bankOperationCode: fields['23B'] ?? '',
        ...amt,
        orderingCustomer: fields['50A'] ?? fields['50K'] ?? '',
        sendingInstitution: fields['52A'] ?? fields['52D'] ?? '',
        orderingInstitution: fields['56A'] ?? fields['56C'] ?? fields['56D'] ?? '',
        beneficiaryCustomer: fields['59'] ?? fields['59A'] ?? '',
        remittanceInfo: fields['70'] ?? '',
        senderToReceiverInfo: fields['72'] ?? '',
    };
}
function parseMt202(fields) {
    const amt = split32A(fields['32A'] ?? '');
    return {
        senderReference: fields['20'] ?? '',
        transactionReference: fields['21'] ?? '',
        ...amt,
        sendingInstitution: fields['52A'] ?? fields['52D'] ?? '',
        orderingInstitution: fields['56A'] ?? fields['56C'] ?? fields['56D'] ?? '',
        accountWithInstitution: fields['57A'] ?? fields['57C'] ?? fields['57D'] ?? '',
        beneficiaryInstitution: fields['58A'] ?? fields['58D'] ?? '',
        remittanceInfo: fields['70'] ?? '',
        senderToReceiverInfo: fields['72'] ?? '',
    };
}
function parseMt910(fields) {
    const amt = split32A(fields['32A'] ?? '');
    return {
        transactionReference: fields['20'] ?? '',
        relatedReference: fields['21'] ?? '',
        ...amt,
        orderingInstitution: fields['52A'] ?? fields['52D'] ?? '',
        accountWithInstitution: fields['57A'] ?? fields['57D'] ?? '',
        remittanceInfo: fields['72'] ?? '',
    };
}
function parseStatement(fields, text) {
    return {
        statementNumber: fields['28C'] ?? '',
        accountIdentification: fields['25'] ?? '',
        openingBalance: fields['60F'] ?? fields['60M'] ?? '',
        closingBalance: fields['62F'] ?? fields['62M'] ?? '',
        transactionLines: (fields['61'] ?? '').split('\n').filter(Boolean),
        narrative: fields['86'] ?? '',
        rawFieldCount: Object.keys(fields).length,
        textLength: text.length,
    };
}
function parseSwiftFin(raw) {
    const lines = raw.trim().split('\n');
    const braceBlocks = extractBraceBlocks(raw);
    const appHeader = parseBlock(lines, 2, braceBlocks);
    const text = parseTextBlock(lines, braceBlocks);
    const messageType = extractMessageType(appHeader);
    const fields = parseSwiftFields(text.startsWith(':') ? text : `\n${text}`);
    let parsed;
    switch (messageType) {
        case 'MT103':
            parsed = parseMt103(fields);
            break;
        case 'MT202':
            parsed = parseMt202(fields);
            break;
        case 'MT910':
            parsed = parseMt910(fields);
            break;
        case 'MT940':
        case 'MT942':
        case 'MT950':
            parsed = parseStatement(fields, text);
            break;
        default:
            parsed = { fields, textPreview: text.slice(0, 500) };
    }
    return {
        format: 'swift_fin',
        messageType,
        raw,
        parsed,
        searchableText: [text, JSON.stringify(parsed), appHeader].join('\n'),
    };
}
function detectInboundFormat(payload) {
    const t = payload.trim();
    if (t.startsWith('{')) {
        try {
            const obj = JSON.parse(t);
            if (obj.format === 'ktt' || obj.messageType === 'KTT' || obj.messageType === 'TELEX_KTT')
                return 'ktt';
            if (obj.event === 'deposit.submitted')
                return 'ktt';
        }
        catch {
            /* continue */
        }
    }
    const upper = t.toUpperCase();
    if (upper.includes('TELEX REF') ||
        upper.startsWith('ORDERING:') ||
        upper.startsWith('BENEFICIARY:') ||
        (t.includes(':20:') && t.includes(':32A:') && !t.startsWith('{1:'))) {
        return 'ktt';
    }
    if (t.startsWith('<?xml') || t.startsWith('<Document'))
        return 'iso20022';
    if (/^\{1:[A-Z0-9]{12}/.test(t) ||
        /^\{2:[IO]\d{3}/.test(t) ||
        /^(\{1:|\d:)/m.test(t) ||
        t.includes(':20:') ||
        /\bMT\d{3}\b/.test(t)) {
        return 'swift_fin';
    }
    if (t.startsWith('{') || t.startsWith('['))
        return 'json_broadcast';
    return 'swift_fin';
}
function parseIso20022(raw) {
    const lower = raw.toLowerCase();
    let messageType = 'unknown';
    if (lower.includes('pacs.008'))
        messageType = 'pacs.008';
    else if (lower.includes('pacs.009'))
        messageType = 'pacs.009';
    else if (lower.includes('pacs.002'))
        messageType = 'pacs.002';
    else if (lower.includes('pain.001'))
        messageType = 'pain.001';
    else if (lower.includes('camt.052'))
        messageType = 'camt.052';
    else if (lower.includes('camt.053'))
        messageType = 'camt.053';
    else if (lower.includes('camt.054'))
        messageType = 'camt.054';
    const tag = (name) => {
        const re = new RegExp(`<(?:[\\w-]+:)?${name}[^>]*>([^<]*)</(?:[\\w-]+:)?${name}>`, 'i');
        return raw.match(re)?.[1]?.trim() ?? '';
    };
    const parsed = {
        messageId: tag('MsgId'),
        instructionId: tag('InstrId'),
        endToEndId: tag('EndToEndId'),
        uetr: tag('UETR'),
        txId: tag('TxId'),
        amount: tag('InstdAmt') || tag('IntrBkSttlmAmt'),
        currency: raw.match(/<(?:[\w-]+:)?InstdAmt[^>]* Ccy="([^"]+)"/i)?.[1] ??
            raw.match(/<(?:[\w-]+:)?IntrBkSttlmAmt[^>]* Ccy="([^"]+)"/i)?.[1] ??
            '',
        debtor: tag('Dbtr') || tag('Nm'),
        creditor: tag('Cdtr'),
        remittance: tag('Ustrd'),
        purpose: tag('Purp'),
    };
    return {
        format: 'iso20022',
        messageType,
        raw,
        parsed,
        searchableText: raw,
    };
}
function parseJsonBroadcast(raw) {
    let parsed;
    try {
        parsed = JSON.parse(raw);
    }
    catch {
        parsed = { raw };
    }
    const messageType = String(parsed.messageType ?? parsed.type ?? parsed.channel ?? parsed.status ?? 'json_broadcast');
    return {
        format: 'json_broadcast',
        messageType,
        raw,
        parsed,
        searchableText: JSON.stringify(parsed),
    };
}
function parseInbound(payload) {
    const trimmed = payload.trim();
    if (trimmed.startsWith('{')) {
        try {
            const obj = JSON.parse(trimmed);
            if (obj.format === 'ktt' || obj.messageType === 'KTT' || obj.messageType === 'TELEX_KTT') {
                return parseKttEnvelope(trimmed, obj);
            }
            if (obj.event === 'deposit.submitted' && obj.payload) {
                return parseKttEnvelope(trimmed, obj.payload);
            }
        }
        catch {
            /* fall through */
        }
    }
    const format = detectInboundFormat(payload);
    if (format === 'ktt')
        return parseKtt(payload);
    if (format === 'swift_fin')
        return parseSwiftFin(payload);
    if (format === 'iso20022')
        return parseIso20022(payload);
    return parseJsonBroadcast(payload);
}
function parseKttEnvelope(raw, obj) {
    const normalizedBody = String(obj.normalizedBody ?? obj.body ?? '');
    const testKeyProof = String(obj.testKeyProof ?? obj.test_key_proof ?? '');
    const messageType = String(obj.messageType ?? obj.msgType ?? '') === 'TELEX_KTT' ? 'TELEX_KTT' : 'KTT';
    const parsed = {
        normalizedBody,
        testKeyProof,
        instructionId: obj.instructionId ?? obj.instruction_id,
        telexRef: obj.telexRef ?? obj.telex_ref,
        debtorId: obj.debtorId,
        creditorId: obj.creditorId,
        amount: obj.amount,
        currency: obj.currency ?? obj.currencyCode,
        authAttestationHash: obj.authAttestationHash ?? obj.auth_attestation_hash,
        ...(obj.normalizedFields ?? {}),
    };
    return {
        format: 'ktt',
        messageType: messageType,
        raw,
        parsed,
        searchableText: [normalizedBody, JSON.stringify(parsed)].join('\n'),
        testKeyProof,
        authAttestationHash: obj.authAttestationHash,
    };
}
function parseKtt(raw) {
    const body = raw.trim();
    const messageType = body.includes(':20:') || body.includes(':32A:') ? 'TELEX_KTT' : 'KTT';
    const parsed = { normalizedBody: body };
    if (messageType === 'TELEX_KTT') {
        const fin = parseSwiftFin(body.includes(':20:') ? `{4:\n${body}\n-}` : body);
        const p = fin.parsed;
        parsed.senderReference = p.senderReference;
        parsed.orderingCustomer = p.orderingCustomer;
        parsed.beneficiaryCustomer = p.beneficiaryCustomer;
        parsed.amount = p.amount;
        parsed.currency = p.currency;
    }
    else {
        for (const line of body.split('\n')) {
            const upper = line.toUpperCase();
            if (upper.startsWith('ORDERING:'))
                parsed.orderingCustomer = line.split(':').slice(1).join(':').trim();
            if (upper.startsWith('BENEFICIARY:'))
                parsed.beneficiaryCustomer = line.split(':').slice(1).join(':').trim();
            if (upper.startsWith('AMOUNT:')) {
                const parts = line.split(':').slice(1).join(':').trim().split(/\s+/);
                if (parts.length >= 2) {
                    parsed.currency = parts[0];
                    parsed.amount = parts[1];
                }
            }
        }
    }
    return {
        format: 'ktt',
        messageType,
        raw,
        parsed,
        searchableText: body,
    };
}
//# sourceMappingURL=inboundParser.js.map