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

const fs = require('fs');
const net = require('net');
const path = require('path');

const projectRoot = path.join(__dirname, '..');
const planRoot = path.join(projectRoot, 'runtime', 'plais-qbft-distributed');
const topologyPath = path.join(planRoot, 'topology.json');
const networkPath = path.join(planRoot, 'network.json');

function validHost(value) {
  const host = String(value || '').trim();
  if (!host || /change|localhost/i.test(host) || host === '127.0.0.1' || host === '0.0.0.0') return false;
  if (net.isIP(host)) return true;
  return /^(?=.{1,253}$)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(host);
}

function main() {
  if (process.env.PLAIS_QBFT_ALLOW_NEW_GENESIS !== '1') {
    throw new Error('Blocked: this package belongs to a different genesis and must not join the canonical candidate network.');
  }
  if (!fs.existsSync(topologyPath) || !fs.existsSync(networkPath)) {
    throw new Error('Run npm run evm:prepare-distributed first.');
  }
  const topology = JSON.parse(fs.readFileSync(topologyPath, 'utf8'));
  const network = JSON.parse(fs.readFileSync(networkPath, 'utf8'));
  if (!Array.isArray(topology.validators) || topology.validators.length !== 5) {
    throw new Error('Exactly five validator PCs are required.');
  }
  const invalid = topology.validators.filter((node) => !validHost(node.advertisedHost));
  if (invalid.length) {
    throw new Error(`Set a reachable VPN/LAN host for: ${invalid.map((node) => node.pcName).join(', ')}`);
  }
  const uniqueHosts = new Set(topology.validators.map((node) => String(node.advertisedHost).toLowerCase()));
  if (uniqueHosts.size !== topology.validators.length) throw new Error('Each physical validator PC needs a unique host address.');

  network.nodes = network.nodes.map((generatedNode) => {
    const configured = topology.validators.find((node) => node.name === generatedNode.name);
    if (!configured) throw new Error(`Topology entry missing for ${generatedNode.name}`);
    return { ...generatedNode, ...configured, finalized: true };
  });

  for (const node of network.nodes) {
    const packageDir = path.join(planRoot, 'packages', node.name);
    const peers = network.nodes.filter((peer) => peer.name !== node.name).map((peer) =>
      `enode://${peer.publicKey}@${peer.advertisedHost}:${peer.p2pPort}`
    );
    fs.writeFileSync(path.join(packageDir, 'static-nodes.json'), `${JSON.stringify(peers, null, 2)}\n`);
    fs.writeFileSync(path.join(packageDir, 'node-config.json'), `${JSON.stringify(node, null, 2)}\n`);
  }
  network.state = 'READY_FOR_PC_INSTALL';
  network.finalizedAt = new Date().toISOString();
  fs.writeFileSync(networkPath, `${JSON.stringify(network, null, 2)}\n`);
  console.log(JSON.stringify({ ok: true, state: network.state, validators: network.nodes.length }));
}

try { main(); } catch (error) { console.error(error.message); process.exit(1); }
