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

const root = path.join(__dirname, '..');
const topology = JSON.parse(fs.readFileSync(path.join(root, 'runtime', 'plais-qbft-canonical-migration', 'topology.json'), 'utf8'));
const runtime = JSON.parse(fs.readFileSync(path.join(root, 'runtime', 'plais-validator-runtime', 'manifest.json'), 'utf8'));
const nodes = persistentStore.readState().nodes || [];
const now = Date.now();
const supportedClientVersions = new Set([
  '1.4.27-validator-presync-deployment-single-install-locked',
  '1.4.28-validator-activation-handoff-single-install-locked',
  '1.4.29-validator-p2p-tunnel-single-install-locked',
  '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'
]);

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

const rows = topology.validators.map(target => {
  const node = latest(target);
  const meta = node?.metadata || {};
  const heartbeatAgeSec = node?.lastHeartbeatAt ? Math.max(0, Math.round((now - new Date(node.lastHeartbeatAt).getTime()) / 1000)) : null;
  const statusAgeSec = meta.validatorRuntimeCheckedAt ? Math.max(0, Math.round((now - new Date(meta.validatorRuntimeCheckedAt).getTime()) / 1000)) : null;
  const checks = {
    active: node?.status === 'active' && heartbeatAgeSec !== null && heartbeatAgeSec <= 180,
    clientReady: supportedClientVersions.has(String(node?.clientVersion || '')),
    statusSchema: meta.validatorRuntimeSchema === 'plais-validator-runtime-deployment-status/v1',
    artifactBound: meta.validatorRuntimeArtifactSha256 === runtime.sha256,
    deviceBound: meta.validatorRuntimeDeviceKeyId === meta.provisioningKeyId,
    statusFresh: statusAgeSec !== null && statusAgeSec <= 180,
    presyncReady: meta.validatorRuntimeState === 'presync-ready',
    validatorActive: meta.validatorRuntimeState === 'validator-active',
    processRunning: Number(meta.validatorRuntimeProcessPid || 0) > 0,
    peerReady: Number(meta.validatorRuntimePeerCount || 0) >= 1,
    blockGapReady: Number(meta.validatorRuntimeGapBlocks || 0) <= 10
  };
  return {
    nodeName: target.nodeName,
    pcName: target.pcName,
    clientVersion: String(node?.clientVersion || ''),
    heartbeatAgeSec,
    runtimeState: String(meta.validatorRuntimeState || ''),
    runtimeVersion: String(meta.validatorRuntimeVersion || ''),
    processPid: Number(meta.validatorRuntimeProcessPid || 0),
    blockNumber: Number(meta.validatorRuntimeBlockNumber || 0),
    canonicalBlock: Number(meta.validatorRuntimeCanonicalBlock || 0),
    gapBlocks: Number(meta.validatorRuntimeGapBlocks || 0),
    peerCount: Number(meta.validatorRuntimePeerCount || 0),
    statusAgeSec,
    diagnostic: String(meta.validatorRuntimeDiagnostic || ''),
    lastFailureDiagnostic: String(meta.validatorRuntimeLastFailureDiagnostic || ''),
    lastLaunchFailedAt: meta.validatorRuntimeLastLaunchFailedAt || null,
    tunnelState: String(meta.validatorTunnelState || ''),
    tunnelApprovalId: String(meta.validatorTunnelApprovalId || ''),
    tunnelTopologyHash: String(meta.validatorTunnelTopologyHash || ''),
    checks,
    ready: Object.entries(checks)
      .filter(([key]) => !['presyncReady', 'validatorActive'].includes(key))
      .every(([, ok]) => ok)
      && (checks.presyncReady || checks.validatorActive)
  };
});

const observedCanonicalBlock = Math.max(0, ...rows.map(row => Number(row.blockNumber || 0)));
for (const row of rows) {
  row.canonicalBlock = Math.max(Number(row.canonicalBlock || 0), observedCanonicalBlock);
  row.gapBlocks = Math.max(0, observedCanonicalBlock - Number(row.blockNumber || 0));
  row.checks.blockGapReady = row.gapBlocks <= 10;
  row.ready = Object.entries(row.checks)
    .filter(([key]) => !['presyncReady', 'validatorActive'].includes(key))
    .every(([, ok]) => ok)
    && (row.checks.presyncReady || row.checks.validatorActive);
}

console.log(JSON.stringify({
  ok: true,
  schemaVersion: 'plais-validator-runtime-deployment-status-report/v1',
  runtime: { version: runtime.version, bytes: runtime.bytes, sha256: runtime.sha256 },
  readyCount: rows.filter(row => row.ready).length,
  allReady: rows.every(row => row.ready),
  rows,
  checkedAt: new Date(now).toISOString()
}, null, 2));
