/**
 * Smoke tests for relay block_validator (no live chain required).
 */
const assert = require("assert");
const bv = require("./block_validator");
const wallet = require("../coordinator_exe/exe_wallet.js");

function emptyMerkle() {
  return bv.merkleRoot([]);
}

function makeHeader(overrides = {}) {
  const merkle = emptyMerkle();
  return {
    version: 1,
    previousBlockHash: "11".repeat(32),
    networkTime: 1_000_033_000,
    timestamp: 1_000_033,
    merkleRoot: merkle,
    difficultyTarget: "f".repeat(64),
    nonce: 0,
    minerPublicKey: "",
    transactionCount: 0,
    founderAddress: "",
    ...overrides,
  };
}

function run() {
  const tip = { height: 10, hash: "11".repeat(32), timestamp: 1_000_000 };
  const header = makeHeader();
  const block = { header, transactions: [], hash: bv.blockHash(header) };

  const good = bv.validateBlockStructure(block, tip, 11);
  assert.strictEqual(good.valid, true, good.message);

  const badMerkle = {
    header: { ...header, merkleRoot: "aa".repeat(32) },
    transactions: [],
  };
  const m = bv.validateBlockStructure(badMerkle, tip, 11);
  assert.strictEqual(m.valid, false);
  assert.match(m.message, /Merkle/i);

  const early = {
    header: makeHeader({ timestamp: tip.timestamp + 10 }),
    transactions: [],
  };
  early.hash = bv.blockHash(early.header);
  const t = bv.validateBlockStructure(early, tip, 11);
  assert.strictEqual(t.valid, false);
  assert.match(t.message, /timestamp/i);

  const kp = wallet.createNewWallet().wallet;
  const prodHeader = makeHeader({ minerPublicKey: kp.publicKeyHex });
  const prodBlock = { header: prodHeader, transactions: [] };
  const expected = kp.address;
  const other = "SRMD" + "1".repeat(40);
  const prodOk = bv.validateProducer(prodBlock, {
    activeAddresses: [expected, other],
    completedAddresses: [],
    remaining: [expected, other],
    claimedProducerAddress: expected,
  });
  assert.strictEqual(prodOk.valid, true, prodOk.message);

  const wrongTurn = bv.validateProducer(prodBlock, {
    activeAddresses: [expected, other],
    completedAddresses: [],
    remaining: [other, expected],
    claimedProducerAddress: expected,
  });
  assert.strictEqual(wrongTurn.valid, false);
  assert.match(wrongTurn.message, /Unexpected producer/);

  // Signed transfer must verify.
  const txUnsigned = {
    fromAddress: expected,
    toAddress: other,
    amount: 1,
    gasFee: 0,
    timestamp: 1_000_000,
    signature: "",
    signerPublicKey: kp.publicKeyHex,
    payloadHex: "",
  };
  const data = Buffer.from(
    `${txUnsigned.fromAddress}|${txUnsigned.toAddress}|${txUnsigned.amount}|${txUnsigned.gasFee}|${txUnsigned.timestamp}|`,
    "utf8"
  );
  const sig = wallet.sign(new Uint8Array(data), kp.privateKey);
  txUnsigned.signature = wallet.bytesToHex(sig);
  const txOk = bv.validateMempoolTx(txUnsigned);
  assert.strictEqual(txOk.valid, true, txOk.message);

  const txBad = { ...txUnsigned, signature: "ab".repeat(100) };
  const txFail = bv.validateMempoolTx(txBad);
  assert.strictEqual(txFail.valid, false);

  console.log("block_validator.test.js: ok");
}

run();
