"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
/**
 * End-to-end smoke test against a live network (default testnet-10).
 * Exercises: resolver connection, server info, address derivation,
 * balance, fee estimation, and local policy enforcement.
 *
 * Usage: npm run build && npm run smoke
 */
const os = __importStar(require("node:os"));
const path = __importStar(require("node:path"));
const fs = __importStar(require("node:fs"));
const policy_1 = require("./policy");
const template_1 = require("./vault/template");
const escrow_template_1 = require("./x402/escrow-template");
const wallet_1 = require("./wallet");
const NETWORK = process.env.SOMPI_NETWORK ?? "testnet-10";
const DATA_DIR = process.env.SOMPI_DATA_DIR ?? path.join(os.homedir(), ".sompi", NETWORK);
async function main() {
    let failures = 0;
    const check = (name, cond, detail = "") => {
        console.log(`${cond ? "PASS" : "FAIL"}  ${name}${detail ? ` — ${detail}` : ""}`);
        if (!cond)
            failures++;
    };
    // --- offline checks: policy engine ---
    const policy = new policy_1.PolicyEngine(os.tmpdir());
    check("policy: defaults load", policy.policy.maxSompiPerTx === 100000000n);
    let denied = false;
    try {
        policy.authorize("kaspatest:qq000", 200000000n);
    }
    catch (e) {
        denied = e instanceof policy_1.PolicyViolation;
    }
    check("policy: per-tx cap denies 2 KAS", denied);
    denied = false;
    try {
        policy.authorize("kaspatest:qq000", -5n);
    }
    catch (e) {
        denied = e instanceof policy_1.PolicyViolation;
    }
    check("policy: negative amount denied", denied);
    policy.record(450000000n);
    denied = false;
    try {
        policy.authorize("kaspatest:qq000", 100000000n);
    }
    catch (e) {
        denied = e instanceof policy_1.PolicyViolation;
    }
    check("policy: hourly cap denies after 4.5 KAS spent", denied);
    // --- offline checks: policy hot-reload ---
    const hotDir = fs.mkdtempSync(path.join(os.tmpdir(), "sompi-smoke-"));
    const hotPolicyPath = path.join(hotDir, "policy.json");
    fs.writeFileSync(hotPolicyPath, JSON.stringify({ maxSompiPerTx: "100", maxSompiPerHour: "1000" }));
    const hotEngine = new policy_1.PolicyEngine(hotDir, hotPolicyPath);
    let hotDenied = false;
    try {
        hotEngine.authorize("kaspatest:qq000", 200n);
    }
    catch {
        hotDenied = true;
    }
    // rewrite with a looser cap and a bumped mtime; no new engine instance
    fs.writeFileSync(hotPolicyPath, JSON.stringify({ maxSompiPerTx: "500", maxSompiPerHour: "1000" }));
    fs.utimesSync(hotPolicyPath, new Date(), new Date(Date.now() + 5));
    let hotAllowed = true;
    try {
        hotEngine.authorize("kaspatest:qq000", 200n);
    }
    catch {
        hotAllowed = false;
    }
    check("policy: hot-reload picks up file edits without restart", hotDenied && hotAllowed);
    fs.writeFileSync(hotPolicyPath, "{not json");
    fs.utimesSync(hotPolicyPath, new Date(), new Date(Date.now() + 10));
    let hotFailedClosed = false;
    try {
        hotEngine.authorize("kaspatest:qq000", 1n);
    }
    catch (e) {
        hotFailedClosed = e instanceof policy_1.PolicyViolation && e.message.includes("malformed");
    }
    check("policy: malformed file fails closed", hotFailedClosed);
    fs.rmSync(hotDir, { recursive: true, force: true });
    // --- offline checks: vault template byte-equality vs compiler fixtures ---
    const fixtures = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "scripts", "vault-fixtures.json"), "utf8"));
    let templateMatches = 0;
    for (const f of fixtures) {
        const redeem = (0, template_1.bytesToHex)((0, template_1.buildRedeemScript)(f.agent, f.owner, BigInt(f.maxOutflow)));
        const withdrawArgs = (0, template_1.bytesToHex)((0, template_1.buildSigArgs)(new Uint8Array(65).fill(0xab), "withdraw"));
        const recoverArgs = (0, template_1.bytesToHex)((0, template_1.buildSigArgs)(new Uint8Array(65).fill(0xab), "recover"));
        if (redeem === f.redeemScript && withdrawArgs === f.withdrawArgsWithDummySig && recoverArgs === f.recoverArgsWithDummySig) {
            templateMatches++;
        }
        else {
            console.log(`  fixture mismatch: agent=${f.agent.slice(0, 8)} max=${f.maxOutflow}`);
        }
    }
    check(`vault template: byte-identical to compiler output (${templateMatches}/${fixtures.length} fixtures)`, templateMatches === fixtures.length);
    // --- offline checks: escrow template byte-equality vs compiler fixtures ---
    const escrowFixtures = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "scripts", "escrow-fixtures.json"), "utf8"));
    let escrowMatches = 0;
    for (const f of escrowFixtures) {
        const redeem = (0, template_1.bytesToHex)((0, escrow_template_1.buildEscrowRedeemScript)(f.client, f.server, BigInt(f.timeout)));
        const claim = (0, template_1.bytesToHex)((0, escrow_template_1.buildClaimArgs)(new Uint8Array(65).fill(0xab), new Uint8Array(64).fill(0xcd), new Uint8Array(8).fill(0xef)));
        const refund = (0, template_1.bytesToHex)((0, escrow_template_1.buildRefundArgs)(new Uint8Array(65).fill(0xab)));
        if (redeem === f.redeemScript && claim === f.claimArgsWithDummies && refund === f.refundArgsWithDummySig) {
            escrowMatches++;
        }
        else {
            console.log(`  escrow fixture mismatch: client=${f.client.slice(0, 8)} timeout=${f.timeout}`);
        }
    }
    check(`escrow template: byte-identical to compiler output (${escrowMatches}/${escrowFixtures.length} fixtures)`, escrowMatches === escrowFixtures.length);
    // --- online checks: live network ---
    if (process.env.SOMPI_SMOKE_OFFLINE) {
        console.log(`\nSOMPI_SMOKE_OFFLINE set; skipping live network checks.`);
        console.log(`\n${failures === 0 ? "ALL CHECKS PASSED" : `${failures} CHECK(S) FAILED`}`);
        process.exit(failures === 0 ? 0 : 1);
    }
    console.log(`\nConnecting to ${NETWORK} via public resolver...`);
    const wallet = new wallet_1.KaspaWallet({ networkId: NETWORK, dataDir: DATA_DIR, nodeUrl: process.env.SOMPI_NODE_URL });
    check("wallet: address derived", wallet.address.length > 0, wallet.address);
    try {
        const info = await wallet.serverInfo();
        check("rpc: connected to node", true, `version ${info.serverVersion}, synced=${info.isSynced}`);
        check("rpc: node has utxoindex", info.hasUtxoIndex === true);
        check("rpc: virtual DAA score sane", BigInt(info.virtualDaaScore) > 0n, `daa=${info.virtualDaaScore}`);
        const balance = await wallet.balanceSompi();
        check("rpc: balance query", balance >= 0n, `${(0, wallet_1.formatKas)(balance)} KAS`);
        const fees = await wallet.feeEstimate();
        const normal = fees.estimate?.normalBuckets?.[0]?.feerate;
        check("rpc: fee estimate", normal !== undefined, `normal feerate=${normal} sompi/gram`);
    }
    catch (e) {
        check("rpc: live network checks", false, e instanceof Error ? e.message : String(e));
    }
    finally {
        await wallet.disconnect();
    }
    console.log(`\n${failures === 0 ? "ALL CHECKS PASSED" : `${failures} CHECK(S) FAILED`}`);
    process.exit(failures === 0 ? 0 : 1);
}
main();
