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

const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const { getServiceSecret } = require('../config/serviceCredentials');
const { signRequestPayload } = require('../middleware/serviceAuth');
const nodeParticipantService = require('../services/nodeParticipantService');

async function main() {
  const serviceName = 'AISFOR';
  const secret = getServiceSecret(serviceName);
  if (!secret) throw new Error('AISFOR chain service credential is not configured.');

  const topology = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'runtime', 'plais-qbft-canonical-migration', 'topology.json'), 'utf8'));
  const allNodes = nodeParticipantService.listNodes();
  const rows = [];
  for (const target of topology.validators || []) {
    const node = allNodes
      .filter((row) => String(row.pcName || '').toLowerCase() === String(target.pcName || '').toLowerCase())
      .sort((left, right) => new Date(right.lastHeartbeatAt || 0) - new Date(left.lastHeartbeatAt || 0))[0];
    if (!node) throw new Error(`Validator candidate is missing: ${target.pcName}`);
    const requestPath = '/api/node/provisioning';
    const body = {
      sourceService: serviceName,
      nodeId: String(node.nodeId || node.id || '')
    };
    const timestamp = String(Date.now());
    const nonce = `${Date.now()}-${crypto.randomBytes(12).toString('hex')}`;
    const signature = signRequestPayload(serviceName, body, secret, {
      timestamp,
      nonce,
      method: 'POST',
      path: requestPath
    });
    const response = await fetch(`http://127.0.0.1:4317${requestPath}`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-AISFOR-SERVICE': serviceName,
        'X-AISFOR-API-KEY': secret,
        'X-AISFOR-SIGNATURE': signature,
        'X-AISFOR-TIMESTAMP': timestamp,
        'X-AISFOR-NONCE': nonce
      },
      body: JSON.stringify(body)
    });
    const result = await response.json().catch(() => ({}));
    if (!response.ok || result.ok !== true || !result.manifest) {
      throw new Error(`Provisioning endpoint failed for ${target.pcName} (${response.status}): ${result.error || result.message || 'unknown'}`);
    }
    const manifest = result.manifest;
    const controls = manifest.controls || {};
    const readOnly = controls.arbitraryCommandAllowed === false
      && controls.packageInstallAllowed === false
      && controls.validatorKeyImportAllowed === false
      && controls.validatorStartAllowed === false;
    const transportReady = manifest.transport?.mode === 'outbound-public-bridge'
      && manifest.transport?.outboundOnly === true
      && manifest.transport?.validatorInboundPortRequired === false
      && manifest.transport?.sourceAddressAllowlisted === true
      && /^enode:\/\/[a-f0-9]{128}@[0-9.]+:[0-9]+$/i.test(String(manifest.transport?.bridgeEnode || ''));
    if (!readOnly || !transportReady) throw new Error(`Provisioning safety or bridge transport failed: ${target.pcName}`);
    rows.push({
      pcName: manifest.pcName,
      nodeName: manifest.assignment?.targetNodeName || '',
      role: manifest.assignment?.role || '',
      state: manifest.assignment?.state || '',
      deviceKeyReady: manifest.encryption?.deviceKeyReady === true,
      transport: manifest.transport?.mode || '',
      sourceAddressAllowlisted: manifest.transport?.sourceAddressAllowlisted === true,
      readOnly
    });
  }

  console.log(JSON.stringify({
    ok: true,
    schemaVersion: 'plais-node-provisioning/v1',
    validatorCount: rows.length,
    transport: 'outbound-public-bridge',
    readOnly: rows.every((row) => row.readOnly),
    rows
  }, null, 2));
}

main().catch((error) => {
  console.error(JSON.stringify({ ok: false, error: error.message }, null, 2));
  process.exit(1);
});
