"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CHAIN138_ATTESTATION_IFACE = exports.DIRECTION_DEBITED = exports.DIRECTION_CREDITED = void 0;
exports.buildTopLevelSurfaceTargets = buildTopLevelSurfaceTargets;
exports.surfaceParticipantsOnMainnet = surfaceParticipantsOnMainnet;
exports.surfaceTopLevelZeroEth = surfaceTopLevelZeroEth;
const ethers_1 = require("ethers");
const checkpoint_core_1 = require("@dbis/checkpoint-core");
const leafCodec_1 = require("./leafCodec");
const SURFACE_ABI = [
    'function notifyBatch(uint64 batchId, tuple(address participant,bytes32 chain138TxHash,bytes32 instructionId,uint8 direction,uint64 batchId,uint256 valueWei,uint64 valueUsdE8)[] items) external',
    'function notified(bytes32) view returns (bool)',
    'function notificationKey(address participant, bytes32 chain138TxHash, uint8 direction) view returns (bytes32)',
];
exports.DIRECTION_CREDITED = 0;
exports.DIRECTION_DEBITED = 1;
/** Matches Chain138ParticipantSurface wallet touch + top-level relayer calldata. */
exports.CHAIN138_ATTESTATION_IFACE = new ethers_1.ethers.Interface([
    'function chain138Attestation(bytes32 chain138TxHash, uint8 direction, uint64 batchId)',
]);
/** One top-level mainnet tx per (participant, chain138TxHash, direction) — both wallets per 138 payment. */
function buildTopLevelSurfaceTargets(leaves, batchId) {
    const seen = new Set();
    const out = [];
    for (const leaf of leaves) {
        const pairs = [
            { participant: leaf.from, direction: exports.DIRECTION_DEBITED },
            { participant: leaf.to, direction: exports.DIRECTION_CREDITED },
        ];
        for (const { participant, direction } of pairs) {
            if (!participant || participant === ethers_1.ethers.ZeroAddress)
                continue;
            const key = `${participant.toLowerCase()}:${leaf.txHash}:${direction}`;
            if (seen.has(key))
                continue;
            seen.add(key);
            out.push({
                participant,
                chain138TxHash: leaf.txHash,
                direction,
                batchId,
                blockNumber: leaf.blockNumber,
            });
        }
    }
    return out;
}
function buildNotifications(leaves, batchId) {
    const items = [];
    for (const leaf of leaves) {
        const iso = leaf.iso20022 ?? (0, checkpoint_core_1.mapPaymentLeafToCanonical)(leaf);
        const usd = leaf.totalTransfersUsd ?? leaf.valueUsd ?? leaf.nativeValueUsd ?? '0';
        const valueWei = (0, leafCodec_1.effectiveValue)(leaf);
        const valueUsdE8 = (0, checkpoint_core_1.usdStringToE8)(usd);
        items.push({
            participant: leaf.from,
            chain138TxHash: leaf.txHash,
            instructionId: iso.instructionIdBytes32,
            direction: exports.DIRECTION_DEBITED,
            batchId,
            valueWei,
            valueUsdE8,
        });
        items.push({
            participant: leaf.to,
            chain138TxHash: leaf.txHash,
            instructionId: iso.instructionIdBytes32,
            direction: exports.DIRECTION_CREDITED,
            batchId,
            valueWei,
            valueUsdE8,
        });
    }
    return items;
}
async function surfaceParticipantsOnMainnet(wallet, surfaceAddress, batchId, leaves) {
    if (!surfaceAddress || leaves.length === 0)
        return null;
    const surface = new ethers_1.ethers.Contract(surfaceAddress, SURFACE_ABI, wallet);
    const all = buildNotifications(leaves, batchId);
    const pending = [];
    for (const item of all) {
        const key = await surface.notificationKey(item.participant, item.chain138TxHash, item.direction);
        try {
            if (await surface.notified(key))
                continue;
        }
        catch {
            /* continue */
        }
        pending.push(item);
    }
    if (pending.length === 0)
        return null;
    const tx = await surface.notifyBatch(batchId, pending.map((p) => ({
        participant: p.participant,
        chain138TxHash: p.chain138TxHash,
        instructionId: p.instructionId,
        direction: p.direction,
        batchId: p.batchId,
        valueWei: p.valueWei,
        valueUsdE8: p.valueUsdE8,
    })), { gasLimit: 5000000n });
    await tx.wait();
    return tx.hash;
}
/**
 * One top-level 0 ETH tx TO each participant role (sender + receiver per Chain 138 tx).
 * Shows on each wallet's Etherscan **Transactions** tab; calldata carries chain138TxHash.
 */
async function surfaceTopLevelZeroEth(wallet, leaves, batchId) {
    const targets = buildTopLevelSurfaceTargets(leaves, batchId);
    let count = 0;
    for (const item of targets) {
        const code = await wallet.provider.getCode(item.participant);
        if (code !== '0x') {
            console.warn(`  skip top-level surface for contract wallet ${item.participant} (use Internal Txns / surface events)`);
            continue;
        }
        const data = exports.CHAIN138_ATTESTATION_IFACE.encodeFunctionData('chain138Attestation', [
            item.chain138TxHash,
            item.direction,
            item.batchId,
        ]);
        try {
            const tx = await wallet.sendTransaction({
                to: item.participant,
                value: 0n,
                data,
                gasLimit: 55000n,
            });
            const receipt = await tx.wait();
            if (receipt?.status !== 1) {
                console.warn(`  top-level surface reverted for ${item.participant} tx=${tx.hash}`);
                continue;
            }
            count++;
        }
        catch (e) {
            console.warn(`  top-level surface failed for ${item.participant}`, e);
        }
    }
    return count;
}
