const fs = require('fs');
const crypto = require('crypto');
const persistentStore = require('./persistentStore');
const dbLedgerAdapter = require('./dbLedgerAdapter');

const COLLECTIONS = [
  { key: 'proofs', collection: 'chain_proofs', label: 'Proof Ledger' },
  { key: 'transactions', collection: 'chain_transactions', label: 'Chain Transactions' },
  { key: 'blocks', collection: 'chain_blocks', label: 'Blocks' },
  { key: 'callbackEvents', collection: 'chain_callbacks', label: 'Callbacks' },
  { key: 'nodes', collection: 'node_participants', label: 'Node Participants' },
  { key: 'nodeEconomyEntries', collection: 'node_economy_ledger', label: 'Node Economy Ledger' },
  { key: 'pointEntries', collection: 'point_ledger', label: 'Point Ledger' },
  { key: 'validatorVotes', collection: 'validator_votes', label: 'Validator Votes' },
  { key: 'backupIndexes', collection: 'backup_indexes', label: 'Backup Indexes' },
  { key: 'distributedChunks', collection: 'distributed_chunks', label: 'Distributed Chunks' },
  { key: 'wallets', collection: 'wallets', label: 'Wallets' },
  { key: 'walletTransactions', collection: 'wallet_transactions', label: 'Wallet Transactions' }
];

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 readShadowRows(filePath) {
  try {
    const rows = JSON.parse(fs.readFileSync(filePath, 'utf8'));
    return Array.isArray(rows) ? rows : [];
  } catch (err) {
    return null;
  }
}

function compareCollection(state, shadowStatus, item) {
  const sourceRows = Array.isArray(state[item.key]) ? state[item.key] : [];
  const shadowMeta = (shadowStatus.collections || []).find((row) => row.collection === item.collection);
  const shadowRows = shadowMeta ? readShadowRows(shadowMeta.filePath) : null;
  const sourceHashes = sourceRows.map((row) => sha256(stableStringify(row)));
  const shadowHashes = Array.isArray(shadowRows) ? shadowRows.map((row) => row._sourceHash || '') : [];
  const sourceHash = sha256(stableStringify(sourceHashes));
  const shadowHash = sha256(stableStringify(shadowHashes));
  const countMatches = sourceRows.length === shadowHashes.length;
  const hashMatches = sourceHash === shadowHash;
  const ok = Boolean(shadowRows) && countMatches && hashMatches;

  return {
    key: item.key,
    collection: item.collection,
    label: item.label,
    ok,
    sourceCount: sourceRows.length,
    shadowCount: shadowHashes.length,
    countMatches,
    hashMatches,
    sourceHash,
    shadowHash,
    filePath: shadowMeta ? shadowMeta.filePath : '',
    issue: ok ? '' : (!shadowRows ? 'shadow file missing' : (countMatches ? 'hash mismatch' : 'count mismatch'))
  };
}

function getStatus() {
  const state = persistentStore.readState();
  const shadowStatus = dbLedgerAdapter.getStatus();
  const checkedAt = new Date().toISOString();
  const collections = COLLECTIONS.map((item) => compareCollection(state, shadowStatus, item));
  const totalSourceRows = collections.reduce((sum, row) => sum + row.sourceCount, 0);
  const totalShadowRows = collections.reduce((sum, row) => sum + row.shadowCount, 0);
  const issueCount = collections.filter((row) => !row.ok).length;

  return {
    ok: issueCount === 0 && totalSourceRows === totalShadowRows && totalSourceRows > 0,
    checkedAt,
    latestShadowSync: shadowStatus.latestSyncedAt,
    totalSourceRows,
    totalShadowRows,
    issueCount,
    collections
  };
}

module.exports = {
  getStatus
};
