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');
const mongoReadAdapter = require('../services/mongoLedgerReadAdapter');
const readiness = require('../services/ledgerDbReadinessService');

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));
}

function isConfirmed() {
  return process.argv.includes('--confirm-live-backfill') || process.env.AISFOR_CHAIN_LEDGER_LIVE_BACKFILL_APPROVED === '1';
}

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

  const status = readiness.getStatus();
  const confirmed = isConfirmed();
  const createdAt = new Date().toISOString();
  const state = persistentStore.readState();
  const collections = migrationService.buildCollectionDocuments(state, createdAt);
  const totalDocuments = collections.reduce((sum, item) => sum + item.docs.length, 0);
  const outputPath = path.join(getDataDir(), 'mongo-live-backfill-latest.json');

  if (!status.readSwitchPreflightOk) {
    throw new Error(`Read-switch preflight is not ready: ${status.switchLockReason}`);
  }

  if (!confirmed) {
    const locked = {
      ok: false,
      mode: 'mongo-live-backfill-locked',
      writesLiveCollections: false,
      reason: 'Pass --confirm-live-backfill or set AISFOR_CHAIN_LEDGER_LIVE_BACKFILL_APPROVED=1 to write live Mongo collections.',
      totalDocuments,
      outputPath,
      checkedAt: createdAt
    };
    fs.writeFileSync(outputPath, JSON.stringify(locked, null, 2) + '\n');
    console.log(JSON.stringify(locked, null, 2));
    process.exitCode = 1;
    return;
  }

  const client = new MongoClient(uri, { serverSelectionTimeoutMS: 5000 });
  await client.connect();
  try {
    const db = client.db();
    const rows = [];

    for (const item of collections) {
      const col = db.collection(item.collection);
      const docs = item.docs.map((doc) => ({
        ...doc,
        _id: doc._migrationId,
        _ledgerLiveKind: mongoReadAdapter.LIVE_KIND,
        _ledgerLiveTargetCollection: item.collection,
        _ledgerLiveCreatedAt: createdAt
      }));

      await col.deleteMany({ _ledgerLiveKind: mongoReadAdapter.LIVE_KIND });
      if (docs.length) await col.insertMany(docs, { ordered: false });
      await col.createIndex({ _ledgerLiveKind: 1, _sourceIndex: 1 });
      await col.createIndex({ _sourceHash: 1 });
      await col.createIndex({ _migrationId: 1 }, { unique: true });

      rows.push({ key: item.key, collection: item.collection, documents: docs.length });
    }

    const run = {
      ok: true,
      mode: 'mongo-live-backfill',
      writesLiveCollections: true,
      liveKind: mongoReadAdapter.LIVE_KIND,
      ledgerPath: getLedgerPath(),
      ledgerHash: readFileHash(getLedgerPath()),
      totalDocuments: rows.reduce((sum, row) => sum + row.documents, 0),
      collections: rows,
      createdAt,
      path: outputPath
    };

    await db.collection('ledger_live_meta').updateOne(
      { _id: 'latest-ledger-json-live-backfill' },
      { $set: run, $push: { history: { createdAt, totalDocuments: run.totalDocuments, ledgerHash: run.ledgerHash } } },
      { upsert: true }
    );

    fs.writeFileSync(outputPath, JSON.stringify(run, null, 2) + '\n');
    console.log(JSON.stringify(run, null, 2));
  } finally {
    await client.close();
  }
}

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