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

const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const { MongoClient } = require('mongodb');
const persistentStore = require('../services/persistentStore');
const migrationService = require('../services/ledgerMigrationService');

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

function getDbUri() {
  return process.env.AISFOR_CHAIN_LEDGER_DB_URI || process.env.DATABASE_URL || process.env.MONGODB_URI || '';
}

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

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

function readFileHash(filePath) {
  return sha256(fs.readFileSync(filePath));
}

async function main() {
  const uri = getDbUri();
  if (!uri) throw new Error('AISFOR_CHAIN_LEDGER_DB_URI is required for staging backfill.');

  const createdAt = new Date().toISOString();
  const state = persistentStore.readState();
  const collections = migrationService.buildCollectionDocuments(state, createdAt);
  const ledgerPath = getLedgerPath();
  const dryRun = migrationService.getLatestDryRun();
  const client = new MongoClient(uri, { serverSelectionTimeoutMS: 5000 });

  await client.connect();
  try {
    const db = client.db();
    const metaCollection = db.collection('migration_staging_meta');
    const results = [];

    for (const item of collections) {
      const stagingName = `migration_staging_${item.collection}`;
      const collection = db.collection(stagingName);
      await collection.deleteMany({ _stagingKind: 'ledger-json-backfill' });

      const docs = item.docs.map((doc) => ({
        ...doc,
        _id: doc._migrationId,
        _stagingKind: 'ledger-json-backfill',
        _stagingTargetCollection: item.collection,
        _stagingCreatedAt: createdAt
      }));

      if (docs.length) {
        await collection.insertMany(docs, { ordered: false });
      }

      await collection.createIndex({ _migrationId: 1 }, { unique: true });
      await collection.createIndex({ _sourceHash: 1 });
      await collection.createIndex({ _stagingKind: 1 });

      results.push({
        key: item.key,
        stagingCollection: stagingName,
        targetCollection: item.collection,
        count: docs.length,
        firstIds: docs.slice(0, 3).map((doc) => doc._migrationId.slice(0, 16))
      });
    }

    const totalDocuments = results.reduce((sum, row) => sum + row.count, 0);
    const run = {
      _id: 'latest-ledger-json-backfill',
      mode: 'staging-only',
      writesLiveCollections: false,
      targetBackend: process.env.AISFOR_CHAIN_LEDGER_TARGET_BACKEND || 'mongodb',
      ledgerPath,
      ledgerHash: readFileHash(ledgerPath),
      dryRunPath: dryRun.dryRunPath || '',
      dryRunHash: dryRun.exists ? readFileHash(dryRun.dryRunPath) : '',
      dryRunTotalDocuments: dryRun.totalDocuments || 0,
      totalDocuments,
      collections: results,
      createdAt,
      updatedAt: createdAt
    };

    await metaCollection.updateOne(
      { _id: run._id },
      { $set: run, $push: { history: { createdAt, totalDocuments, ledgerHash: run.ledgerHash, dryRunHash: run.dryRunHash } } },
      { upsert: true }
    );

    const output = { ok: true, ...run, path: path.join(getDataDir(), 'migration-staging-latest.json') };
    fs.writeFileSync(output.path, JSON.stringify(output, null, 2) + '\n');
    console.log(JSON.stringify(output, null, 2));
  } finally {
    await client.close();
  }
}

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


