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

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

const migrationRoot = path.join(__dirname, '..', 'runtime', 'plais-qbft-canonical-migration');
const approvalPath = path.join(migrationRoot, 'validator-activation-approval.json');
const topologyPath = path.join(migrationRoot, 'topology.json');
const supportedClientVersions = new Set([
  '1.4.30-validator-tunnel-approval-retry-single-install-locked',
  '1.4.31-validator-envelope-identity-rotation-single-install-locked',
  '1.4.32-validator-bridge-fallback-single-install-locked',
  '1.4.33-validator-presync-bridge-recovery-single-install-locked',
  '1.4.34-validator-runtime-diagnostic-single-install-locked',
  '1.4.35-validator-runtime-worker-guard-single-install-locked',
  '1.4.36-validator-memory-safe-single-install-locked',
  '1.4.37-validator-rpc-ready-recovery-single-install-locked',
  '1.4.38-validator-startup-monitor-single-install-locked',
  '1.4.39-validator-error-retention-single-install-locked',
  '1.4.40-validator-exit-code-diagnostic-single-install-locked',
  '1.4.41-validator-complete-exit-diagnostic-single-install-locked',
  '1.4.42-validator-dll-basename-diagnostic-single-install-locked',
  '1.4.43-validator-app-local-vc-runtime-single-install-locked',
  '1.4.44-validator-snap-presync-single-install-locked',
  '1.4.45-validator-activation-diagnostic-single-install-locked',
  '1.4.46-validator-failure-retention-single-install-locked',
  '1.4.47-validator-worker-lock-identity-single-install-locked',
  '1.4.48-validator-runtime-pid-identity-single-install-locked',
  '1.4.49-validator-tunnel-state-preservation-single-install-locked',
  '1.4.50-validator-worker-race-single-install-locked',
  '1.4.51-validator-orphan-worker-cleanup-single-install-locked',
  '1.4.52-validator-existing-besu-adoption-single-install-locked',
  '1.4.53-validator-static-topology-reconcile-single-install-locked',
  '1.4.54-validator-preserved-full-bridge-recovery-single-install-locked',
  '1.4.55-validator-tunnel-approval-refresh-single-install-locked',
  '1.4.56-validator-directed-tunnel-topology-single-install-locked',
  '1.4.57-validator-loopback-tunnel-peer-diagnostic-single-install-locked',
  '1.4.58-validator-launch-config-reconcile-single-install-locked',
  '1.4.59-validator-p2p-disconnect-diagnostic-single-install-locked',
  '1.4.60-validator-unique-advertised-endpoint-single-install-locked',
  '1.4.61-validator-active-data-path-reconcile-single-install-locked',
  '1.4.62-validator-approved-consensus-restart-single-install-locked',
  '1.4.63-validator-qbft-consensus-diagnostic-single-install-locked',
  '1.4.107-quick-tunnel-discovery-default-off-locked',
  '1.4.109-runtime-heartbeat-null-stale-fallback-default-off-locked',
  '1.4.110-data-replica-readiness-attestation-default-off-locked',
  '1.4.111-validator-node-mode-recovery-single-install-locked'
  ,'1.4.112-validator-control-error-attestation-single-install-locked'
  ,'1.4.113-validator-control-evidence-priority-single-install-locked'
  ,'1.4.114-validator-runtime-evidence-priority-single-install-locked'
  ,'1.4.115-validator-active-tunnel-restart-stability-single-install-locked'
  ,'1.4.116-validator-active-tunnel-restart-stability-single-install-locked'
  ,'1.4.117-validator-direct-lan-quorum-tunnel-fallback-locked'
  ,'1.4.118-validator-direct-lan-runtime-attestation-tunnel-fallback-locked'
  ,'1.4.119-validator-direct-nodeinfo-attestation-tunnel-fallback-locked'
  ,'1.4.120-validator-direct-attestation-refresh-tunnel-fallback-locked'
  ,'1.4.121-validator-direct-evidence-diagnostic-tunnel-fallback-locked'
  ,'1.4.122-validator-direct-offer-state-diagnostic-tunnel-fallback-locked'
  ,'1.4.123-validator-direct-control-heartbeat-diagnostic-tunnel-fallback-locked'
]);

if (!fs.existsSync(approvalPath)) throw new Error('Validator activation approval is missing.');
const approval = JSON.parse(fs.readFileSync(approvalPath, 'utf8'));
const topology = JSON.parse(fs.readFileSync(topologyPath, 'utf8'));
const target = (topology.validators || []).find(row => row.nodeName === approval.nodeName);
if (!target) throw new Error('Validator activation target is invalid.');

const nodes = persistentStore.readState().nodes || [];
const node = nodes.filter(row => matchesValidatorTarget(row, target))
  .sort((a, b) => new Date(b.lastHeartbeatAt || 0) - new Date(a.lastHeartbeatAt || 0))[0];
const meta = node?.metadata || {};
const heartbeatAgeMs = Date.now() - new Date(node?.lastHeartbeatAt || 0).getTime();
const runtimeAgeMs = Date.now() - new Date(meta.validatorRuntimeCheckedAt || 0).getTime();
const controls = approval.controls || {};
const approvedAtMs = new Date(approval.approvedAt || 0).getTime();
const expiresAtMs = new Date(approval.expiresAt || 0).getTime();
const runtimeCheckedAtMs = new Date(meta.validatorRuntimeCheckedAt || 0).getTime();
const exactApprovalBound = meta.validatorRuntimeApprovalId === approval.approvalId;
const activeWithinApprovalWindow = !meta.validatorRuntimeApprovalId
  && Number.isFinite(approvedAtMs) && Number.isFinite(expiresAtMs) && Number.isFinite(runtimeCheckedAtMs)
  && approvedAtMs <= runtimeCheckedAtMs && runtimeCheckedAtMs <= expiresAtMs + 3 * 60_000
  && Date.now() <= expiresAtMs;

const checks = {
  approvalSchema: approval.schemaVersion === 'plais-validator-activation-approval/v1',
  approvalAction: approval.action === 'ACTIVATE_REMOTE_VALIDATOR_AFTER_CANONICAL_STOP',
  nodeActive: node?.status === 'active',
  heartbeatFresh: heartbeatAgeMs >= 0 && heartbeatAgeMs <= 3 * 60_000,
  runtimeFresh: runtimeAgeMs >= 0 && runtimeAgeMs <= 3 * 60_000,
  clientVersion: supportedClientVersions.has(node?.clientVersion),
  validatorActive: meta.validatorRuntimeState === 'validator-active',
  approvalBound: exactApprovalBound || activeWithinApprovalWindow,
  processRunning: Number(meta.validatorRuntimeProcessPid || 0) > 0,
  peerReady: Number(meta.validatorRuntimePeerCount || 0) >= 1,
  blockGapReady: Number(meta.validatorRuntimeGapBlocks || 0) <= 10,
  tunnelSchema: meta.validatorTunnelSchema === 'plais-validator-p2p-tunnel/v1',
  tunnelApplied: ['direct-peers-applied', 'direct-lan-quorum-with-tunnel-fallback-applied'].includes(meta.validatorTunnelState),
  tunnelTopologyBound: /^[a-f0-9]{64}$/.test(String(meta.validatorTunnelTopologyHash || '')),
  keyDecryptApproved: controls.validatorKeyDecryptAllowed === true,
  keyImportApproved: controls.validatorKeyImportAllowed === true,
  validatorStartApproved: controls.validatorStartAllowed === true,
  publicRpcLocked: controls.publicRpcAllowed === false,
  externalTransactionLocked: controls.externalTransactionAllowed === false,
  operatorSigningLocked: controls.operatorSigningAllowed === false,
  arbitraryCommandLocked: controls.arbitraryCommandAllowed === false
};
if (!Object.values(checks).every(Boolean)) {
  throw new Error(`Fresh remote validator activation evidence is incomplete: ${Object.entries(checks).filter(([, ok]) => !ok).map(([name]) => name).join(',')}`);
}

const historyRoot = path.join(migrationRoot, 'approval-history');
fs.mkdirSync(historyRoot, { recursive: true });
const archivePath = path.join(historyRoot, `${approval.approvalId}-complete.json`);
if (fs.existsSync(archivePath)) throw new Error('Validator activation approval archive already exists.');
fs.renameSync(approvalPath, archivePath);
console.log(JSON.stringify({
  ok: true,
  status: 'REMOTE_VALIDATOR_ACTIVATION_APPROVAL_ARCHIVED',
  nodeName: approval.nodeName,
  approvalId: approval.approvalId,
  approvalBindingEvidence: exactApprovalBound ? 'exact-runtime-approval-id' : 'active-within-single-approval-window',
  processPid: Number(meta.validatorRuntimeProcessPid),
  archivePath
}, null, 2));
