"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSettlementRouter = createSettlementRouter;
const express_1 = require("express");
const settlement_core_1 = require("@dbis/settlement-core");
const config_1 = require("../../config");
const external_transfer_1 = require("../../workflows/external-transfer");
const token_load_1 = require("../../workflows/token-load");
const transfer_1 = require("../../workflows/transfer");
const office_scope_1 = require("../../workflows/office-scope");
const settlement_store_1 = require("../../store/settlement-store");
const swift_inbound_1 = require("../../workflows/swift-inbound");
const fineract_1 = require("../../adapters/fineract");
const auth_1 = require("../../middleware/auth");
async function respondPublicMoneySupply(res, officeId) {
    const cfg = (0, config_1.loadConfig)();
    const allow = cfg.production.onlineBankMode || process.env.OMNL_PUBLIC_MONEY_SUPPLY === '1';
    if (!allow) {
        res.status(404).json({ error: 'Public money supply disabled' });
        return;
    }
    try {
        const [balances, fineractConnected] = await Promise.all([
            (0, fineract_1.fetchGlBalances)(officeId),
            (0, fineract_1.fineractOfficeReachable)(officeId),
        ]);
        const snapshot = (0, settlement_core_1.buildMoneySupplySnapshot)(officeId, balances);
        const hasActivity = Object.values(balances).some((v) => Math.abs(parseFloat(v) || 0) > 0);
        res.json({
            ...snapshot,
            fineractConnected,
            fineractLive: fineractConnected && hasActivity,
            interoffice: {
                dueFromHeadOffice: balances['1410'] ?? '0',
                gl1410: balances['1410'] ?? '0',
            },
        });
    }
    catch (e) {
        res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
    }
}
function createSettlementRouter() {
    const router = (0, express_1.Router)();
    const officeId = (0, config_1.settlementOfficeId)();
    const profile = (0, config_1.loadOfficeProfile)();
    router.get('/health/ledger', (_req, res) => respondPublicMoneySupply(res, officeId));
    router.get('/health', async (req, res) => {
        let chainStats = { total: 0, active: 0 };
        try {
            const reg = (0, settlement_core_1.loadOmnlChainRegistry)();
            chainStats = { total: reg.chains.length, active: (0, settlement_core_1.getActiveChains)().length };
        }
        catch {
            /* optional */
        }
        const payload = {
            service: 'omnl-settlement-middleware',
            status: 'ok',
            mode: process.env.SETTLEMENT_MIDDLEWARE_CONFIG?.includes('production') ? 'production' : 'standard',
            role: 'OMNL central-bank settlement orchestration',
            chainSupport: { max: 128, ...chainStats },
            settlementOffice: {
                officeId: profile.officeId,
                externalId: profile.externalId,
                name: profile.name,
            },
            enforceSingleOffice: (0, config_1.loadConfig)().enforceSingleOffice ?? false,
        };
        const includeLedger = req.query.ledger === '1' ||
            req.query.include === 'money-supply' ||
            req.query.include === 'ledger';
        if (includeLedger) {
            const cfg = (0, config_1.loadConfig)();
            const allow = cfg.production.onlineBankMode || process.env.OMNL_PUBLIC_MONEY_SUPPLY === '1';
            if (allow) {
                try {
                    const [balances, fineractConnected] = await Promise.all([
                        (0, fineract_1.fetchGlBalances)(officeId),
                        (0, fineract_1.fineractOfficeReachable)(officeId),
                    ]);
                    const snapshot = (0, settlement_core_1.buildMoneySupplySnapshot)(officeId, balances);
                    const hasActivity = Object.values(balances).some((v) => Math.abs(parseFloat(v) || 0) > 0);
                    payload.moneySupply = {
                        ...snapshot,
                        fineractConnected,
                        fineractLive: fineractConnected && hasActivity,
                        interoffice: {
                            dueFromHeadOffice: balances['1410'] ?? '0',
                            gl1410: balances['1410'] ?? '0',
                        },
                    };
                }
                catch (e) {
                    payload.moneySupplyError = e instanceof Error ? e.message : String(e);
                }
            }
        }
        res.json(payload);
    });
    router.get('/office', (_req, res) => {
        res.json({
            ...profile,
            locked: true,
            storePath: `data/settlement-store/office-${officeId}`,
        });
    });
    router.get('/public/money-supply', (_req, res) => respondPublicMoneySupply(res, officeId));
    router.get('/money-supply/public', (_req, res) => respondPublicMoneySupply(res, officeId));
    router.get('/money-supply', async (req, res) => {
        if (!(0, auth_1.requireApiKey)(req, res))
            return;
        try {
            res.json(await (0, external_transfer_1.getMoneySupply)(officeId));
        }
        catch (e) {
            res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.get('/money-supply/:officeIdParam', async (req, res) => {
        if (!(0, auth_1.requireApiKey)(req, res))
            return;
        const requested = parseInt(req.params.officeIdParam, 10);
        if (!Number.isFinite(requested)) {
            res.status(404).json({ error: 'Not found' });
            return;
        }
        try {
            res.json(await (0, external_transfer_1.getMoneySupply)((0, config_1.settlementOfficeId)(requested)));
        }
        catch (e) {
            res.status(400).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.get('/settlements', (req, res) => {
        if (!(0, auth_1.requireApiKey)(req, res))
            return;
        res.json({
            officeId,
            items: settlement_store_1.settlementStore.list(Number(req.query.limit ?? 50)),
        });
    });
    router.get('/settlements/:id', (req, res) => {
        if (!(0, auth_1.requireApiKey)(req, res))
            return;
        const rec = (0, external_transfer_1.getSettlementStatus)(req.params.id);
        if (!rec) {
            res.status(404).json({ error: 'Not found' });
            return;
        }
        res.json(rec);
    });
    router.post('/external-transfer', async (req, res) => {
        if (!(0, auth_1.requireApiKey)(req, res))
            return;
        try {
            const merged = (0, office_scope_1.bindOffice24)(req.body);
            const record = await (0, external_transfer_1.processExternalTransfer)(merged);
            res.status(record.phase === 'FAILED' ? 422 : 200).json(record);
        }
        catch (e) {
            res.status(e instanceof Error && e.message.includes('locked') ? 403 : 500).json({
                error: e instanceof Error ? e.message : String(e),
            });
        }
    });
    router.post('/swift/inbound', async (req, res) => {
        if (!(0, auth_1.requireApiKey)(req, res))
            return;
        try {
            const raw = typeof req.body === 'string' ? req.body : req.body?.raw;
            if (!raw) {
                res.status(400).json({ error: 'raw SWIFT payload required' });
                return;
            }
            const record = await (0, swift_inbound_1.processSwiftInbound)(String(raw));
            res.json(record);
        }
        catch (e) {
            res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.post('/trade-finance/:instrument', async (req, res) => {
        if (!(0, auth_1.requireApiKey)(req, res))
            return;
        const instrument = req.params.instrument.toUpperCase();
        if (!['SBLC', 'DLC', 'BG', 'LS'].includes(instrument)) {
            res.status(400).json({ error: 'Invalid instrument' });
            return;
        }
        try {
            const body = req.body;
            const merged = (0, office_scope_1.bindOffice24)({
                ...body,
                tradeFinance: {
                    instrument,
                    reference: body.tradeFinance?.reference ?? body.idempotencyKey,
                    expiryDate: body.tradeFinance?.expiryDate,
                },
                rail: 'SWIFT',
                moneyLayers: body.moneyLayers ?? ['M1', 'M2'],
            });
            const record = await (0, external_transfer_1.processExternalTransfer)(merged);
            res.status(record.phase === 'FAILED' ? 422 : 200).json(record);
        }
        catch (e) {
            res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.post('/convert/fiat-to-crypto', async (req, res) => {
        if (!(0, auth_1.requireApiKey)(req, res))
            return;
        try {
            const body = req.body;
            const merged = (0, office_scope_1.bindOffice24)({
                ...body,
                rail: body.rail ?? 'INTERNAL',
                convertToCrypto: {
                    enabled: true,
                    targetChainId: body.convertToCrypto?.targetChainId ?? 138,
                    tokenLineId: body.convertToCrypto?.tokenLineId ?? `${body.currency ?? 'USD'}-M2`,
                    recipientAddress: body.convertToCrypto?.recipientAddress ?? '',
                },
                moneyLayers: ['M2'],
            });
            const record = await (0, external_transfer_1.processExternalTransfer)(merged);
            res.status(record.phase === 'FAILED' ? 422 : 200).json(record);
        }
        catch (e) {
            res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.post('/token-load', async (req, res) => {
        if (!(0, auth_1.requireApiKey)(req, res))
            return;
        try {
            const body = req.body;
            if (!body.idempotencyKey || !body.lineId || !body.amount || !body.recipientAddress) {
                res.status(400).json({ error: 'idempotencyKey, lineId, amount, recipientAddress required' });
                return;
            }
            const record = await (0, token_load_1.processTokenLoad)({
                ...body,
                officeId: (0, config_1.settlementOfficeId)(body.officeId),
            });
            res.status(record.phase === 'FAILED' ? 422 : 200).json(record);
        }
        catch (e) {
            res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.post('/transfer/internal', async (req, res) => {
        if (!(0, auth_1.requireApiKey)(req, res))
            return;
        try {
            const body = req.body;
            if (!body.idempotencyKey || !body.tokenAddress || !body.amount || !body.recipientAddress) {
                res.status(400).json({ error: 'idempotencyKey, tokenAddress, amount, recipientAddress required' });
                return;
            }
            const record = await (0, transfer_1.processTransfer)({
                ...body,
                officeId: (0, config_1.settlementOfficeId)(body.officeId),
                rail: 'INTERNAL',
                moneyLayers: body.moneyLayers ?? ['M2'],
            });
            res.status(record.phase === 'FAILED' ? 422 : 200).json(record);
        }
        catch (e) {
            res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.post('/transfer/external', async (req, res) => {
        if (!(0, auth_1.requireApiKey)(req, res))
            return;
        try {
            const body = req.body;
            if (!body.creditorIban) {
                res.status(400).json({ error: 'creditorIban required for external transfer' });
                return;
            }
            const record = await (0, transfer_1.processTransfer)({
                ...body,
                officeId: (0, config_1.settlementOfficeId)(body.officeId),
                rail: body.rail === 'RTGS' ? 'RTGS' : 'SWIFT',
                moneyLayers: body.moneyLayers ?? ['M2'],
            });
            res.status(record.phase === 'FAILED' ? 422 : 200).json(record);
        }
        catch (e) {
            res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.get('/tokens/m2', (_req, res) => {
        try {
            const fs = require('fs');
            const path = require('path');
            const p = process.env.OMNL_M2_TOKEN_REGISTRY ||
                path.resolve(__dirname, '../../../../../config/omnl-m2-token-registry.v1.json');
            const registry = JSON.parse(fs.readFileSync(p, 'utf8'));
            res.json(registry);
        }
        catch (e) {
            res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.get('/chains', (_req, res) => {
        try {
            const registry = (0, settlement_core_1.loadOmnlChainRegistry)();
            res.json({
                brand: registry.brand,
                maxCapacity: registry.maxCapacity,
                primaryChainId: registry.primaryChainId,
                mirrorChainId: registry.mirrorChainId,
                settlementOfficeId: registry.settlementOfficeId,
                stats: registry.stats,
                chains: registry.chains,
            });
        }
        catch (e) {
            res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.get('/chains/active', (_req, res) => {
        try {
            res.json({ count: (0, settlement_core_1.getActiveChains)().length, chains: (0, settlement_core_1.getActiveChains)() });
        }
        catch (e) {
            res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    return router;
}
