"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.exchangePort = void 0;
exports.createExchangeRouter = createExchangeRouter;
const express_1 = require("express");
const config_1 = require("../../config");
Object.defineProperty(exports, "exchangePort", { enumerable: true, get: function () { return config_1.exchangePort; } });
const settlement_1 = require("../../adapters/settlement");
const token_aggregation_1 = require("../../adapters/token-aggregation");
const swap_monitor_1 = require("../../store/swap-monitor");
const auth_1 = require("../../middleware/auth");
function createExchangeRouter() {
    const router = (0, express_1.Router)();
    const cfg = (0, config_1.loadExchangeConfig)();
    router.get('/health', (_req, res) => {
        res.json({
            service: 'dbis-exchange',
            brand: cfg.brandName,
            chainId: cfg.chainId,
            officeId: cfg.officeId,
            settlementOffice: cfg.settlementOfficeExternalId,
            tokenAggregation: (0, config_1.tokenAggUrl)(),
            settlementMiddleware: (0, config_1.settlementUrl)(),
            status: 'ok',
        });
    });
    router.get('/tokens', (req, res) => {
        if (!(0, auth_1.requireRead)(req, res))
            return;
        const tokens = (0, config_1.loadExchangeTokens)();
        res.json({
            chainId: cfg.chainId,
            tokens,
            count: tokens.length,
            moneyLayer: 'M2',
            routers: cfg.routers,
        });
    });
    router.get('/tokens/capabilities', (req, res) => {
        if (!(0, auth_1.requireRead)(req, res))
            return;
        const registry = (0, config_1.loadM2TokenRegistry)();
        res.json(registry);
    });
    router.get('/providers', async (req, res) => {
        if (!(0, auth_1.requireRead)(req, res))
            return;
        try {
            res.json(await (0, token_aggregation_1.fetchProviderCapabilities)(cfg.chainId));
        }
        catch (e) {
            res.status(502).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.get('/quote', async (req, res) => {
        if (!(0, auth_1.requireRead)(req, res))
            return;
        try {
            const tokenIn = String(req.query.tokenIn || '');
            const tokenOut = String(req.query.tokenOut || '');
            const amountIn = String(req.query.amountIn || '');
            if (!tokenIn || !tokenOut || !amountIn) {
                res.status(400).json({ error: 'tokenIn, tokenOut, amountIn required' });
                return;
            }
            const quote = await (0, token_aggregation_1.fetchQuote)({
                chainId: cfg.chainId,
                tokenIn,
                tokenOut,
                amountIn,
            });
            if (cfg.production.monitorSwaps) {
                (0, swap_monitor_1.recordSwap)({
                    officeId: cfg.officeId,
                    chainId: cfg.chainId,
                    tokenIn,
                    tokenOut,
                    amountIn,
                    amountOut: quote.amountOut ?? quote.expectedOutput,
                    status: 'QUOTED',
                });
            }
            res.json(quote);
        }
        catch (e) {
            res.status(502).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.post('/plan', async (req, res) => {
        if (!(0, auth_1.requireTrade)(req, res))
            return;
        try {
            const { tokenIn, tokenOut, amountIn, recipient, maxSlippageBps } = req.body;
            if (!tokenIn || !tokenOut || !amountIn) {
                res.status(400).json({ error: 'tokenIn, tokenOut, amountIn required' });
                return;
            }
            const plan = await (0, token_aggregation_1.fetchRoutePlan)({
                sourceChainId: cfg.chainId,
                destinationChainId: cfg.chainId,
                tokenIn: String(tokenIn),
                tokenOut: String(tokenOut),
                amountIn: String(amountIn),
                recipient: recipient ? String(recipient) : undefined,
                maxSlippageBps: maxSlippageBps ? Number(maxSlippageBps) : cfg.defaultSlippageBps,
            });
            res.json(plan);
        }
        catch (e) {
            res.status(502).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.post('/execute-plan', async (req, res) => {
        if (!(0, auth_1.requireTrade)(req, res))
            return;
        try {
            const { tokenIn, tokenOut, amountIn, recipient, maxSlippageBps } = req.body;
            if (!tokenIn || !tokenOut || !amountIn || !recipient) {
                res.status(400).json({ error: 'tokenIn, tokenOut, amountIn, recipient required' });
                return;
            }
            const plan = await (0, token_aggregation_1.fetchExecutionPlan)({
                sourceChainId: cfg.chainId,
                destinationChainId: cfg.chainId,
                tokenIn: String(tokenIn),
                tokenOut: String(tokenOut),
                amountIn: String(amountIn),
                recipient: String(recipient),
                maxSlippageBps: maxSlippageBps ? Number(maxSlippageBps) : cfg.defaultSlippageBps,
            });
            res.json(plan);
        }
        catch (e) {
            res.status(502).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.get('/ledgers', async (req, res) => {
        if (!(0, auth_1.requireRead)(req, res))
            return;
        try {
            const wallet = req.query.wallet ? String(req.query.wallet) : undefined;
            const serverKey = process.env.OMNL_API_KEY;
            const rpc = process.env.RPC_URL_138_PUBLIC ||
                process.env.RPC_URL_138 ||
                'https://rpc-http-pub.d-bis.org';
            let fund = null;
            let office = null;
            if (serverKey) {
                [fund, office] = await Promise.all([
                    (0, settlement_1.fetchFundLedger)(cfg.officeId, serverKey),
                    (0, settlement_1.fetchOfficeProfile)(),
                ]);
            }
            let crypto;
            if (wallet) {
                crypto = await (0, settlement_1.fetchCryptoLedger)(rpc, wallet, (0, config_1.loadExchangeTokens)());
            }
            res.json({
                officeId: cfg.officeId,
                office,
                fundLedger: fund?.fundLedger ?? null,
                cryptoLedger: crypto ?? null,
                asOf: new Date().toISOString(),
            });
        }
        catch (e) {
            res.status(502).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.get('/swap/monitor', (req, res) => {
        if (!(0, auth_1.requireSuperAdmin)(req, res))
            return;
        res.json({ stats: (0, swap_monitor_1.swapStats)(), swaps: (0, swap_monitor_1.listSwaps)(Number(req.query.limit ?? 50)) });
    });
    router.post('/swap/record', (req, res) => {
        if (!(0, auth_1.requireTrade)(req, res))
            return;
        const body = req.body;
        const rec = (0, swap_monitor_1.recordSwap)({
            officeId: cfg.officeId,
            chainId: cfg.chainId,
            tokenIn: String(body.tokenIn ?? ''),
            tokenOut: String(body.tokenOut ?? ''),
            amountIn: String(body.amountIn ?? ''),
            amountOut: body.amountOut ? String(body.amountOut) : undefined,
            txHash: body.txHash ? String(body.txHash) : undefined,
            wallet: body.wallet ? String(body.wallet) : undefined,
            routeProviders: Array.isArray(body.routeProviders)
                ? body.routeProviders.map(String)
                : undefined,
            status: body.status ?? 'SUBMITTED',
            settlementRef: body.settlementRef ? String(body.settlementRef) : undefined,
        });
        res.json(rec);
    });
    router.patch('/swap/record/:id', (req, res) => {
        if (!(0, auth_1.requireSuperAdmin)(req, res))
            return;
        const updated = (0, swap_monitor_1.updateSwap)(req.params.id, req.body);
        if (!updated) {
            res.status(404).json({ error: 'Not found' });
            return;
        }
        res.json(updated);
    });
    router.post('/swap/settle', async (req, res) => {
        if (!(0, auth_1.requireSuperAdmin)(req, res))
            return;
        if (!cfg.production.postSwapSettlementAudit) {
            res.status(403).json({ error: 'postSwapSettlementAudit disabled' });
            return;
        }
        try {
            const { swapId, amount, recipientAddress, currency, tokenLineId, tokenSymbol } = req.body;
            const tokens = (0, config_1.loadExchangeTokens)();
            const token = tokens.find((t) => t.symbol === tokenSymbol);
            const lineId = tokenLineId
                ? String(tokenLineId)
                : token
                    ? (0, settlement_1.resolveTokenLine)(token)
                    : `${String(currency ?? 'USD')}-M2`;
            const audit = await (0, settlement_1.auditSwapToSettlement)({
                idempotencyKey: `SWAP-${String(swapId ?? Date.now())}`,
                amount: String(amount ?? '0'),
                currency: String(currency ?? 'USD'),
                recipientAddress: String(recipientAddress ?? ''),
                remittanceInfo: `DBIS Exchange M2 swap settlement Office ${cfg.officeId}`,
                tokenLineId: lineId,
                apiKey: (0, auth_1.apiKey)(req),
            });
            if (swapId)
                (0, swap_monitor_1.updateSwap)(String(swapId), { settlementRef: audit.settlementId, status: 'CONFIRMED' });
            res.json(audit);
        }
        catch (e) {
            res.status(502).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.post('/token-load', async (req, res) => {
        if (!(0, auth_1.requireSuperAdmin)(req, res))
            return;
        try {
            const body = req.body;
            const tokens = (0, config_1.loadExchangeTokens)();
            const addr = String(body.tokenAddress ?? '');
            const token = tokens.find((t) => t.address.toLowerCase() === addr.toLowerCase());
            const result = await (0, settlement_1.requestM2TokenLoad)({
                idempotencyKey: String(body.idempotencyKey ?? `LOAD-${Date.now()}`),
                lineId: String(body.lineId ?? token?.omnlLine ?? 'USD-M2'),
                symbol: String(body.symbol ?? token?.symbol ?? ''),
                tokenAddress: addr,
                amount: String(body.amount ?? '0'),
                recipientAddress: String(body.recipientAddress ?? ''),
                currency: String(body.currency ?? token?.currencyCode ?? 'USD'),
                apiKey: (0, auth_1.apiKey)(req) ?? process.env.OMNL_API_KEY,
            });
            res.status(result.phase === 'FAILED' ? 422 : 200).json(result);
        }
        catch (e) {
            res.status(502).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.post('/transfer/internal', async (req, res) => {
        if (!(0, auth_1.requireSuperAdmin)(req, res))
            return;
        try {
            const body = req.body;
            const result = await (0, settlement_1.requestInternalTransfer)({
                idempotencyKey: String(body.idempotencyKey ?? `XFER-INT-${Date.now()}`),
                tokenAddress: String(body.tokenAddress ?? ''),
                tokenSymbol: String(body.tokenSymbol ?? ''),
                amount: String(body.amount ?? '0'),
                recipientAddress: String(body.recipientAddress ?? ''),
                senderAddress: body.senderAddress ? String(body.senderAddress) : undefined,
                apiKey: (0, auth_1.apiKey)(req) ?? process.env.OMNL_API_KEY,
            });
            res.status(result.phase === 'FAILED' ? 422 : 200).json(result);
        }
        catch (e) {
            res.status(502).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    router.post('/transfer/external', async (req, res) => {
        if (!(0, auth_1.requireSuperAdmin)(req, res))
            return;
        try {
            const body = req.body;
            const result = await (0, settlement_1.requestExternalTransfer)({
                idempotencyKey: String(body.idempotencyKey ?? `XFER-EXT-${Date.now()}`),
                tokenAddress: String(body.tokenAddress ?? ''),
                tokenSymbol: String(body.tokenSymbol ?? ''),
                amount: String(body.amount ?? '0'),
                recipientAddress: String(body.recipientAddress ?? ''),
                creditorIban: String(body.creditorIban ?? ''),
                beneficiaryName: body.beneficiaryName ? String(body.beneficiaryName) : undefined,
                currency: body.currency ? String(body.currency) : undefined,
                remittanceInfo: body.remittanceInfo ? String(body.remittanceInfo) : undefined,
                apiKey: (0, auth_1.apiKey)(req) ?? process.env.OMNL_API_KEY,
            });
            res.status(result.phase === 'FAILED' ? 422 : 200).json(result);
        }
        catch (e) {
            res.status(502).json({ error: e instanceof Error ? e.message : String(e) });
        }
    });
    return router;
}
