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

const fs = require('fs');
const path = require('path');
const persistentStore = require('../services/persistentStore');
const { matchesValidatorTarget } = require('../services/validatorTargetBindingService');
const { restrictAcl } = require('../lib/operatorDpapi');

const projectRoot = path.join(__dirname, '..');
const migrationRoot = path.join(projectRoot, 'runtime', 'plais-qbft-canonical-migration');
const topologyPath = path.join(migrationRoot, 'topology.json');
const manifestPath = path.join(migrationRoot, 'encrypted-key-envelopes', 'manifest.json');
const approvalPath = path.join(migrationRoot, 'encrypted-key-delivery-approval.json');
const historyRoot = path.join(migrationRoot, 'approval-history');
const confirmPhrase = 'ARCHIVE_STAGED_VALIDATOR_KEY_DELIVERY_APPROVAL';

function latestNode(nodes, target) {
  return nodes.filter((node) => matchesValidatorTarget(node, target))
    .sort((left, right) => new Date(right.lastHeartbeatAt || 0) - new Date(left.lastHeartbeatAt || 0))[0] || null;
}

function main() {
  const confirm = String(process.argv.find((value) => value.startsWith('--confirm=')) || '').slice('--confirm='.length);
  if (confirm !== confirmPhrase) throw new Error('EXACT_DELIVERY_ARCHIVE_CONFIRMATION_REQUIRED');
  if (!fs.existsSync(approvalPath) || !fs.existsSync(topologyPath) || !fs.existsSync(manifestPath)) {
    throw new Error('DELIVERY_APPROVAL_OR_BINDING_MISSING');
  }
  const topology = JSON.parse(fs.readFileSync(topologyPath, 'utf8'));
  const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
  const approval = JSON.parse(fs.readFileSync(approvalPath, 'utf8'));
  const controls = approval.controls || {};
  if (approval.action !== 'DELIVER_ENCRYPTED_VALIDATOR_KEY_ENVELOPES'
    || controls.encryptedEnvelopeDownloadAllowed !== true
    || controls.validatorKeyDecryptAllowed !== false
    || controls.validatorKeyImportAllowed !== false
    || controls.validatorStartAllowed !== false
    || controls.arbitraryCommandAllowed !== false
    || !Array.isArray(topology.validators)
    || topology.validators.length !== 4
    || !Array.isArray(manifest.nodes)
    || manifest.nodes.length !== 4) {
    throw new Error('DELIVERY_APPROVAL_BINDING_INVALID');
  }

  const nodes = persistentStore.readState().nodes || [];
  const now = Date.now();
  const rows = topology.validators.map((target) => {
    const node = latestNode(nodes, target);
    const manifestRow = manifest.nodes.find((row) => row.nodeName === target.nodeName && row.pcName === target.pcName);
    const metadata = node?.metadata || {};
    const heartbeatAt = new Date(node?.lastHeartbeatAt || 0).getTime();
    const deliveryAt = new Date(metadata.validatorKeyDeliveryReceivedAt || 0).getTime();
    const ready = Boolean(node && manifestRow)
      && node.status === 'active'
      && Number.isFinite(heartbeatAt)
      && now - heartbeatAt >= -60_000
      && now - heartbeatAt <= 5 * 60 * 1000
      && metadata.validatorKeyDeliverySchema === 'plais-validator-key-delivery-offer/v1'
      && metadata.validatorKeyDeliveryState === 'encrypted-envelope-staged'
      && metadata.validatorKeyDeliveryDeviceKeyId === manifestRow.deviceKeyId
      && metadata.validatorKeyEnvelopeHash === manifestRow.sha256
      && Number.isFinite(deliveryAt)
      && deliveryAt <= now + 60_000;
    if (!ready) throw new Error(`VALIDATOR_ENVELOPE_STAGE_EVIDENCE_INCOMPLETE:${target.nodeName}`);
    return { nodeName: target.nodeName, pcName: target.pcName };
  });

  fs.mkdirSync(historyRoot, { recursive: true });
  if (!restrictAcl(historyRoot, true).ok) throw new Error('DELIVERY_APPROVAL_HISTORY_ACL_FAILED');
  const safeApprovalId = String(approval.approvalId || '').replace(/[^A-Za-z0-9._-]/g, '_').slice(0, 128);
  if (!safeApprovalId) throw new Error('DELIVERY_APPROVAL_ID_INVALID');
  const destination = path.join(historyRoot, `${safeApprovalId}-staged-4of4.json`);
  const relative = path.relative(path.resolve(historyRoot), path.resolve(destination));
  if (!relative || relative.startsWith('..') || path.isAbsolute(relative) || fs.existsSync(destination)) {
    throw new Error('DELIVERY_APPROVAL_ARCHIVE_PATH_INVALID');
  }
  fs.renameSync(approvalPath, destination);
  if (!restrictAcl(destination, false).ok) throw new Error('ARCHIVED_DELIVERY_APPROVAL_ACL_FAILED');

  console.log(JSON.stringify({
    ok: true,
    state: 'ENCRYPTED_VALIDATOR_KEY_DELIVERY_STAGED_AND_RELOCKED',
    validatorCount: rows.length,
    encryptedEnvelopeStaged: true,
    validatorKeyDecryptAllowed: false,
    validatorKeyImportAllowed: false,
    validatorStartAllowed: false,
    standingDeliveryApproval: false,
    archivedApproval: path.basename(destination)
  }, null, 2));
}

try {
  main();
} catch (error) {
  console.error(JSON.stringify({ ok: false, error: error.message }));
  process.exit(1);
}
