const fs = require('fs');
const {
  BASE1_DATA_PATH,
  appendBase1ConfirmationBlock,
  getBase1Account,
  getCurrentBase1Public,
  loadBase1State,
  makeCandidateFromOfficial,
  resetBase1State,
  submitBase1Candidate,
  submitBase1Transfer,
  verifyBase1Chain,
} = require('../src/lib/base1_state');

function candidateForCurrentStep() {
  const state = loadBase1State();
  return makeCandidateFromOfficial(state.officialStepsByKey[state.currentStepKey]);
}

function solveAndConfirm(solver) {
  const solve = submitBase1Candidate({
    solver,
    candidateStep: candidateForCurrentStep(),
    expectedHead: getCurrentBase1Public().latest_head_guard,
  });
  if (!solve.correct) throw new Error(`Solve failed: ${solve.code || solve.message}`);
  appendBase1ConfirmationBlock({ producer: 'transfer-confirm-1' });
  appendBase1ConfirmationBlock({ producer: 'transfer-confirm-2' });
  return solve;
}

function main() {
  const hadState = fs.existsSync(BASE1_DATA_PATH);
  const backup = hadState ? fs.readFileSync(BASE1_DATA_PATH, 'utf8') : null;

  try {
    resetBase1State();
    const sender = 'transfer-solver';
    const receiver = 'transfer-receiver';
    solveAndConfirm(sender);
    const before = getBase1Account(sender);
    const amount = Math.max(1, Math.floor(before.confirmed_balance / 2));
    const fee = 1;
    const transfer = submitBase1Transfer({
      from: sender,
      to: receiver,
      amount,
      fee,
      nonce: before.nonce + 1,
      expectedHead: getCurrentBase1Public().latest_head_guard,
    });
    if (!transfer.ok) throw new Error(`Transfer failed: ${transfer.code || transfer.message}`);

    const senderAfter = getBase1Account(sender);
    const receiverAfter = getBase1Account(receiver);
    if (senderAfter.confirmed_balance !== before.confirmed_balance - amount - fee) {
      throw new Error('Sender balance mismatch after transfer');
    }
    if (receiverAfter.confirmed_balance !== amount) {
      throw new Error('Receiver balance mismatch after transfer');
    }
    const chain = verifyBase1Chain();
    if (!chain.ok) throw new Error(`Chain verification failed: ${chain.code}`);

    console.table([
      {
        account: sender,
        before_confirmed: before.confirmed_balance,
        after_confirmed: senderAfter.confirmed_balance,
        nonce: senderAfter.nonce,
      },
      {
        account: receiver,
        before_confirmed: 0,
        after_confirmed: receiverAfter.confirmed_balance,
        nonce: receiverAfter.nonce,
      },
      {
        account: 'chain',
        before_confirmed: '',
        after_confirmed: chain.cumulative_work_score,
        nonce: `height ${chain.height}`,
      },
    ]);
  } finally {
    if (hadState) {
      fs.writeFileSync(BASE1_DATA_PATH, backup, 'utf8');
    } else if (fs.existsSync(BASE1_DATA_PATH)) {
      fs.unlinkSync(BASE1_DATA_PATH);
    }
  }
}

main();
