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

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

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

  try {
    resetBase1State();
    const solver = 'reward-solver';
    const result = submitBase1Candidate({
      solver,
      candidateStep: candidateForCurrentStep(),
      expectedHead: getCurrentBase1Public().latest_head_guard,
    });
    if (!result.correct) throw new Error(`Solve failed: ${result.code || result.message}`);

    const afterSolve = getBase1Account(solver);
    const rewardAfterSolve = getBase1RewardLedger({ limit: 1 })[0];
    if (afterSolve.pending_balance <= 0 || afterSolve.confirmed_balance !== 0) {
      throw new Error('Expected reward to be pending after solve');
    }
    if (rewardAfterSolve.status !== 'pending') throw new Error(`Expected pending reward, got ${rewardAfterSolve.status}`);

    appendBase1ConfirmationBlock({ producer: 'confirm-node-1' });
    const afterOneConfirm = getBase1Account(solver);
    const rewardAfterOneConfirm = getBase1RewardLedger({ limit: 1 })[0];
    if (afterOneConfirm.confirmed_balance !== 0) {
      throw new Error('Reward confirmed too early');
    }
    if (rewardAfterOneConfirm.status !== 'pending') {
      throw new Error(`Expected reward to remain pending, got ${rewardAfterOneConfirm.status}`);
    }

    appendBase1ConfirmationBlock({ producer: 'confirm-node-2' });
    const afterTwoConfirms = getBase1Account(solver);
    const rewardAfterTwoConfirms = getBase1RewardLedger({ limit: 1 })[0];
    if (afterTwoConfirms.pending_balance !== 0 || afterTwoConfirms.confirmed_balance <= 0) {
      throw new Error('Expected reward to become confirmed');
    }
    if (rewardAfterTwoConfirms.status !== 'confirmed') {
      throw new Error(`Expected confirmed reward, got ${rewardAfterTwoConfirms.status}`);
    }

    const chain = verifyBase1Chain();
    if (!chain.ok) throw new Error(`Chain verification failed: ${chain.code}`);

    console.table([
      {
        phase: 'after solve',
        pending: afterSolve.pending_balance,
        confirmed: afterSolve.confirmed_balance,
        reward_status: rewardAfterSolve.status,
      },
      {
        phase: 'after 1 confirm block',
        pending: afterOneConfirm.pending_balance,
        confirmed: afterOneConfirm.confirmed_balance,
        reward_status: rewardAfterOneConfirm.status,
      },
      {
        phase: 'after 2 confirm blocks',
        pending: afterTwoConfirms.pending_balance,
        confirmed: afterTwoConfirms.confirmed_balance,
        reward_status: rewardAfterTwoConfirms.status,
      },
      {
        phase: 'chain',
        pending: '',
        confirmed: chain.cumulative_work_score,
        reward_status: `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();
