require('../config/loadEnv')();

const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const persistentStore = require('../services/persistentStore');
const mongoReadAdapter = require('../services/mongoLedgerReadAdapter');

function sha256(value) {
  return crypto.createHash('sha256').update(String(value)).digest('hex');
}

function stableStringify(value) {
  if (value === null || typeof value !== 'object') return JSON.stringify(value);
  if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`;
  return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`).join(',')}}`;
}

function getDataDir() {
  const info = persistentStore.getStorageInfo ? persistentStore.getStorageInfo() : {};
  return info.dataDir || path.dirname(info.ledgerPath || persistentStore.getLedgerPath());
}

async function main() {
  const jsonState = persistentStore.readState();
  const mongo = await mongoReadAdapter.readStateFromMongo({ ignoreGate: true });
  const rows = mongoReadAdapter.COLLECTIONS.map((item) => {
    const expectedRows = Array.isArray(jsonState[item.key]) ? jsonState[item.key] : [];
    const actualRows = Array.isArray(mongo.state[item.key]) ? mongo.state[item.key] : [];
    const expectedHashes = expectedRows.map((row) => sha256(stableStringify(row)));
    const actualHashes = actualRows.map((row) => sha256(stableStringify(row)));
    const mismatches = [];
    const max = Math.max(expectedHashes.length, actualHashes.length);
    for (let i = 0; i < max && mismatches.length < 5; i += 1) {
      if (expectedHashes[i] !== actualHashes[i]) {
        mismatches.push({ index: i, expected: expectedHashes[i] || null, actual: actualHashes[i] || null });
      }
    }
    return {
      key: item.key,
      collection: item.collection,
      expectedCount: expectedRows.length,
      actualCount: actualRows.length,
      ok: expectedRows.length === actualRows.length && mismatches.length === 0,
      mismatches
    };
  });

  const failed = rows.filter((row) => !row.ok);
  const output = {
    ok: failed.length === 0,
    mode: 'mongo-read-backend-compare',
    readGate: mongoReadAdapter.getStatus(),
    totalExpected: rows.reduce((sum, row) => sum + row.expectedCount, 0),
    totalActual: rows.reduce((sum, row) => sum + row.actualCount, 0),
    failedCollections: failed.length,
    rows,
    checkedAt: new Date().toISOString(),
    path: path.join(getDataDir(), 'mongo-read-backend-compare.json')
  };

  fs.writeFileSync(output.path, JSON.stringify(output, null, 2) + '\n');
  console.log(JSON.stringify(output, null, 2));
  if (failed.length) process.exitCode = 1;
}

main().catch((err) => {
  console.error(JSON.stringify({ ok: false, error: err.message }, null, 2));
  process.exitCode = 1;
});
