const assert = require('assert');
const fs = require('fs');
const path = require('path');

const ROOT = path.resolve(__dirname, '..');
const sampleDir = path.join(ROOT, 'data', 'sharded-storage-sample');
fs.rmSync(sampleDir, { recursive: true, force: true });
fs.mkdirSync(sampleDir, { recursive: true });

process.env.MAZEX_DATA_DIR = sampleDir;
process.env.MAZEX_SHARDED_STORAGE = '1';

const {
  BASE1_DATA_PATH,
  getBase1ChainSummary,
  getCurrentBase1Public,
  loadBase1State,
  makeCandidateFromOfficial,
  replayBase1Chain,
  resetBase1State,
  submitBase1Candidate,
  verifyBase1Chain,
} = require('../src/lib/base1_state');
const {
  loadLatestFromShardedStorage,
  shardedStorageStatus,
} = require('../src/lib/sharded_chain_storage');

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

function solveOnce(index) {
  const accepted = submitBase1Candidate({
    solver: `sharded-solver-${index}`,
    candidateStep: currentCandidate(),
    expectedHead: getCurrentBase1Public().latest_head_guard,
    chargeFee: true,
  });
  assert.strictEqual(accepted.correct, true);
  assert(accepted.solve_block?.block_hash);
  return accepted;
}

function main() {
  resetBase1State();
  for (let i = 0; i < 8; i += 1) solveOnce(i + 1);

  const chain = getBase1ChainSummary();
  const status = shardedStorageStatus();
  assert.strictEqual(status.exists, true);
  assert.strictEqual(status.head.height, chain.height);
  assert.strictEqual(status.head.head_hash, chain.head_hash);
  assert.strictEqual(status.block_count, chain.height + 1);
  assert(status.block_files >= 1);
  assert(status.header_files >= 1);
  assert(status.bytes.blocks > 0);
  assert(status.bytes.state > 0);
  assert(status.bytes.indexes > 0);

  const hydrated = loadLatestFromShardedStorage({ hydrateBlocks: true });
  assert(hydrated);
  assert.strictEqual(hydrated.chain.blocks.length, chain.height + 1);
  assert.strictEqual(hydrated.chain.head_hash, chain.head_hash);
  assert.strictEqual(fs.existsSync(BASE1_DATA_PATH), false);

  const replay = replayBase1Chain({ state: hydrated });
  assert.strictEqual(replay.ok, true);
  assert.strictEqual(verifyBase1Chain().ok, true);

  console.log(
    JSON.stringify(
      {
        status: 'pass',
        height: chain.height,
        block_count: status.block_count,
        block_files: status.block_files,
        header_files: status.header_files,
        json_state_backup_exists: fs.existsSync(BASE1_DATA_PATH),
        bytes: status.bytes,
        head: status.head.head_hash,
      },
      null,
      2,
    ),
  );
}

main();
