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 targetNodeNames = ['validator-1', 'validator-2', 'validator-3'];
const previousPids = String(process.argv.find(value => value.startsWith('--previous-pids=')) || '')
  .slice(16).split(',').map(Number);
const baselineBlock = Number(String(process.argv.find(value => value.startsWith('--baseline-block=')) || '').slice(17));
const confirm = String(process.argv.find(value => value.startsWith('--confirm=')) || '').slice(10);
const expectedConfirm = `ARCHIVE validator-1,validator-2,validator-3 DIRECT LAN RESTART AFTER PIDS ${previousPids.join(',')}`;
if (previousPids.length !== 3
  || previousPids.some(value => !Number.isInteger(value) || value <= 0)
  || new Set(previousPids).size !== 3
  || !Number.isSafeInteger(baselineBlock) || baselineBlock <= 0
  || confirm !== expectedConfirm) {
  throw new Error('Exact observed direct-LAN quorum restart archive confirmation is required.');
}
if (!fs.existsSync(service.paths.approvalPath)) throw new Error('Direct LAN quorum approval is missing.');
const approval = JSON.parse(fs.readFileSync(service.paths.approvalPath, 'utf8'));
if (approval.action !== 'ACTIVATE_VALIDATOR_DIRECT_LAN_QUORUM'
  || JSON.stringify(approval.targetNodeNames || []) !== JSON.stringify(targetNodeNames)
  || approval.controls?.validatorProcessRestartAllowed !== true
  || approval.controls?.directLanQuorumMigration !== true
  || Number(approval.controls?.coordinatedRestartMaxSkewSeconds) !== 180
  || approval.controls?.validatorKeyExportAllowed !== false
  || approval.controls?.publicRpcAllowed !== false
  || approval.controls?.externalTransactionAllowed !== false
  || approval.controls?.operatorSigningAllowed !== false) {
  throw new Error('Direct LAN quorum approval controls are invalid.');
}

const topology = JSON.parse(fs.readFileSync(service.paths.topologyPath, 'utf8'));
const direct = service.getDirectQuorum(topology);
if (!direct || direct.state !== 'STAGED'
  || JSON.stringify(direct.targetNodeNames) !== JSON.stringify(targetNodeNames)) {
  throw new Error('The staged direct LAN quorum topology is invalid.');
}
const nodes = persistentStore.readState().nodes || [];
const requiredClientVersion = '1.4.123-validator-direct-control-heartbeat-diagnostic-tunnel-fallback-locked';
const rows = direct.targets.map((target, index) => {
  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 currentPid = Number(meta.validatorRuntimeProcessPid || 0);
  const blockNumber = Number(meta.validatorRuntimeBlockNumber || 0);
  const heartbeatAgeMs = Date.now() - new Date(node?.lastHeartbeatAt || 0).getTime();
  const statusAgeMs = Date.now() - new Date(meta.validatorRuntimeCheckedAt || 0).getTime();
  const diagnostic = String(meta.validatorRuntimeDiagnostic || '');
  if (node?.status !== 'active'
    || heartbeatAgeMs < 0 || heartbeatAgeMs > 3 * 60_000
    || statusAgeMs < 0 || statusAgeMs > 3 * 60_000
    || node.clientVersion !== requiredClientVersion
    || meta.validatorRuntimeState !== 'validator-active'
    || currentPid <= 0 || currentPid === previousPids[index]
    || blockNumber <= baselineBlock
    || Number(meta.validatorRuntimePeerCount || 0) < 2
    || !diagnostic.includes('configured-port-30303')) {
    throw new Error(`Fresh post-restart direct-peer evidence is incomplete: ${target.nodeName}.`);
  }
  return {
    nodeName: target.nodeName,
    targetHost: target.targetHost,
    previousPid: previousPids[index],
    currentPid,
    blockNumber,
    peerCount: Number(meta.validatorRuntimePeerCount || 0),
    directPeerObserved: true,
    heartbeatAt: node.lastHeartbeatAt,
    runtimeCheckedAt: meta.validatorRuntimeCheckedAt
  };
});
const blocks = rows.map(row => row.blockNumber);
if (Math.max(...blocks) - Math.min(...blocks) > 20) {
  throw new Error('Post-restart direct LAN validator block spread exceeds the completion bound.');
}

const historyRoot = path.join(path.dirname(service.paths.approvalPath), 'approval-history');
fs.mkdirSync(historyRoot, { recursive: true });
const archivePath = path.join(historyRoot, `${approval.approvalId}-direct-lan-restart-observed.json`);
const evidencePath = path.join(historyRoot, `${approval.approvalId}-direct-lan-restart-observed-evidence.json`);
if (fs.existsSync(archivePath) || fs.existsSync(evidencePath)) {
  throw new Error('Observed direct LAN restart archive already exists.');
}
const evidence = {
  schemaVersion: 'plais-validator-direct-lan-restart-observation/v1',
  approvalId: approval.approvalId,
  baselineBlock,
  rows,
  observedAt: new Date().toISOString()
};
const tempEvidencePath = `${evidencePath}.${process.pid}.tmp`;
fs.writeFileSync(tempEvidencePath, `${JSON.stringify(evidence, null, 2)}\n`, { encoding: 'utf8', flag: 'wx' });
try {
  fs.renameSync(service.paths.approvalPath, archivePath);
  fs.renameSync(tempEvidencePath, evidencePath);
} catch (error) {
  try { fs.unlinkSync(tempEvidencePath); } catch (_) {}
  throw error;
}
console.log(JSON.stringify({
  ok: true,
  status: 'DIRECT_LAN_QUORUM_RESTART_APPROVAL_ARCHIVED_FROM_OBSERVED_EVIDENCE',
  approvalId: approval.approvalId,
  baselineBlock,
  rows,
  archivePath,
  evidencePath
}, null, 2));
