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');

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'));
const topology = JSON.parse(fs.readFileSync(service.paths.topologyPath, 'utf8'));
const direct = service.getDirectQuorum(topology);
if (!direct || direct.state !== 'STAGED'
  || !['ACTIVATE_VALIDATOR_DIRECT_LAN_QUORUM', 'ATTEST_EXISTING_VALIDATOR_DIRECT_LAN_QUORUM'].includes(approval.action)
  || JSON.stringify(approval.targetNodeNames || []) !== JSON.stringify(direct.targetNodeNames)) {
  throw new Error('Direct LAN quorum approval or topology is invalid.');
}
const nodes = persistentStore.readState().nodes || [];
const canaryPath = path.join(path.dirname(service.paths.topologyPath), 'direct-lan-outage-canary.json');
let canary = null;
try { canary = JSON.parse(fs.readFileSync(canaryPath, 'utf8')); } catch (_) {}
const canaryRows = new Map((Array.isArray(canary?.postRows) ? canary.postRows : []).map(row => [row.nodeName, row]));
const canaryBaselines = new Map((Array.isArray(canary?.baselineRows) ? canary.baselineRows : []).map(row => [row.nodeName, row]));
const canaryCheckedAt = new Date(canary?.checkedAt || 0).getTime();
const canaryValid = canary?.schemaVersion === 'plais-validator-direct-lan-outage-canary/v1'
  && canary?.status === 'PASSED' && canary?.ok === true
  && canary?.approvalId === approval.approvalId
  && JSON.stringify(canary?.targetNodeNames || []) === JSON.stringify(direct.targetNodeNames)
  && canary?.centralProcessesStoppedTogether === true && canary?.centralProcessesRestored === true
  && Number(canary?.outageSeconds || 0) >= 90
  && Number.isFinite(canaryCheckedAt) && Date.now() - canaryCheckedAt <= 10 * 60_000;
const blockNumbers = [];
for (const target of direct.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();
  const canaryRow = canaryRows.get(target.nodeName);
  const canaryBaseline = canaryBaselines.get(target.nodeName);
  const directStatusValid = meta.validatorTunnelState === 'direct-lan-quorum-with-tunnel-fallback-applied'
    && meta.validatorTunnelApprovalId === approval.approvalId;
  const outageEvidenceValid = canaryValid && canaryRow && canaryBaseline
    && Number(canaryRow.processPid || 0) === Number(canaryBaseline.processPid || 0)
    && Number(canaryRow.processPid || 0) === Number(meta.validatorRuntimeProcessPid || 0)
    && Number(canaryRow.blockNumber || 0) >= Number(canaryBaseline.blockNumber || 0) + 10;
  if (node?.status !== 'active' || ageMs < 0 || ageMs > 3 * 60_000
    || (!directStatusValid && !outageEvidenceValid)
    || Number(meta.validatorRuntimeProcessPid || 0) <= 0
    || Number(meta.validatorRuntimePeerCount || 0) < 2) {
    throw new Error(`Fresh direct LAN application evidence is incomplete: ${target.nodeName}.`);
  }
  blockNumbers.push(Number(meta.validatorRuntimeBlockNumber || 0));
}
if (Math.max(...blockNumbers) - Math.min(...blockNumbers) > 20) throw new Error('Direct LAN quorum block convergence is incomplete.');
const activatedAt = new Date().toISOString();
const nextTopology = {
  ...topology,
  directQuorum: { ...topology.directQuorum, state: 'ACTIVE', activatedAt },
  updatedAt: activatedAt
};
const temporaryPath = `${service.paths.topologyPath}.${process.pid}.tmp`;
fs.writeFileSync(temporaryPath, `${JSON.stringify(nextTopology, null, 2)}\n`, { encoding: 'utf8', flag: 'wx' });
fs.renameSync(temporaryPath, service.paths.topologyPath);
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('Direct LAN quorum approval archive already exists.');
fs.renameSync(service.paths.approvalPath, archivePath);
console.log(JSON.stringify({
  ok: true,
  status: 'DIRECT_LAN_QUORUM_ACTIVE_APPROVAL_ARCHIVED',
  approvalId: approval.approvalId,
  targetNodeNames: direct.targetNodeNames,
  blockRange: { minimum: Math.min(...blockNumbers), maximum: Math.max(...blockNumbers) },
  archivePath,
  activatedAt
}, null, 2));
