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

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

function solveOne(solver) {
  const result = submitBase1Candidate({
    solver,
    candidateStep: candidateForCurrentStep(),
    expectedHead: getCurrentBase1Public().latest_head_guard,
  });
  if (!result.correct) throw new Error(`Solve failed: ${result.code || result.message}`);
  return result;
}

function confirm(times) {
  for (let index = 0; index < times; index += 1) {
    appendBase1ConfirmationBlock({ producer: `replay-confirmation-${index + 1}` });
  }
}

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

  try {
    resetBase1State();
    solveOne('replay-solver');
    confirm(3);
    solveOne('replay-solver');
    confirm(3);

    const account = getBase1Account('replay-solver');
    if (account.confirmed_balance >= 2) {
      const transfer = submitBase1Transfer({
        from: 'replay-solver',
        to: 'replay-receiver',
        amount: 1,
        fee: 1,
        nonce: account.nonce + 1,
        expectedHead: getCurrentBase1Public().latest_head_guard,
        signedPayloadHash: 'sample-state-replay',
      });
      if (!transfer.ok) throw new Error(`Transfer failed: ${transfer.code || transfer.message}`);
    }

    const replay = replayBase1Chain();
    if (!replay.ok) throw new Error(`Replay failed: ${replay.code || replay.message}`);

    console.table([
      {
        phase: 'state replay',
        height: replay.chain.height,
        work: replay.chain.cumulative_work_score,
        checked_blocks: replay.checked_blocks,
        solved: replay.solved_count,
        rewards: replay.reward_count,
        transfers: replay.transfer_count,
        head: replay.chain.head_hash.slice(0, 16),
      },
    ]);
  } finally {
    if (hadState) {
      fs.writeFileSync(BASE1_DATA_PATH, backup, 'utf8');
    } else if (fs.existsSync(BASE1_DATA_PATH)) {
      fs.unlinkSync(BASE1_DATA_PATH);
    }
  }
}

main();
