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

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-retention-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(service.paths.approvalPath)) throw new Error('Validator tunnel migration approval is missing.');
const approval = JSON.parse(fs.readFileSync(service.paths.approvalPath, 'utf8'));
const topology = JSON.parse(fs.readFileSync(service.paths.topologyPath, 'utf8'));
const coordinatedNodeNames = ['validator-1', 'validator-2', 'validator-3', 'validator-4'];
const coordinated = approval.action === 'RESTART_VALIDATOR_SET_FOR_QBFT_CONSENSUS_RECOVERY'
  && JSON.stringify(approval.targetNodeNames || []) === JSON.stringify(coordinatedNodeNames)
  && approval.controls?.coordinatedConsensusRecovery === true;
const targetNames = coordinated ? coordinatedNodeNames : [approval.nodeName];
const targets = targetNames.map(nodeName => (topology.validators || []).find(row => row.nodeName === nodeName));
if (targets.some(target => !target)) throw new Error('Validator tunnel migration target is invalid.');
const nodes = persistentStore.readState().nodes || [];
for (const target of targets) {
  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 ageMs = Date.now() - new Date(node?.lastHeartbeatAt || 0).getTime();
  if (
    node?.status !== 'active'
    || ageMs < 0 || ageMs > 3 * 60_000
    || !supportedClientVersions.has(node.clientVersion)
    || meta.validatorTunnelSchema !== 'plais-validator-p2p-tunnel/v1'
    || !['direct-peers-applied', 'direct-lan-quorum-with-tunnel-fallback-applied'].includes(meta.validatorTunnelState)
    || meta.validatorTunnelApprovalId !== approval.approvalId
    || !/^[a-f0-9]{64}$/.test(String(meta.validatorTunnelTopologyHash || ''))
    || Number(meta.validatorRuntimeProcessPid || 0) <= 0
  ) throw new Error(`Fresh validator tunnel application evidence is incomplete: ${target.nodeName}.`);
}
const historyRoot = path.join(path.dirname(service.paths.approvalPath), 'approval-history');
fs.mkdirSync(historyRoot, { recursive: true });
const archivePath = path.join(historyRoot, `${approval.approvalId}-complete.json`);
if (fs.existsSync(archivePath)) throw new Error('Validator tunnel approval archive already exists.');
fs.renameSync(service.paths.approvalPath, archivePath);
console.log(JSON.stringify({
  ok: true,
  status: 'VALIDATOR_TUNNEL_MIGRATION_APPROVAL_ARCHIVED',
  ...(coordinated ? { targetNodeNames: targetNames } : { nodeName: approval.nodeName }),
  approvalId: approval.approvalId,
  archivePath
}, null, 2));
