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

const fs = require('fs');
const path = require('path');
const { JsonRpcProvider, ZeroAddress, getAddress, isAddress } = require('ethers');
const { EVM_CANDIDATE_CONFIG } = require('../config/evmCandidateConfig');
const { CANONICAL_LEDGER_CONFIG, isCanonicalBesuQbft } = require('../config/canonicalLedgerConfig');

const projectRoot = path.join(__dirname, '..');
const profilePath = path.join(projectRoot, 'config', 'exchangeIntegration.example.json');
const reportPath = path.join(projectRoot, 'docs', 'listing', '06-exchange-integration', 'evidence', 'internal-readiness.json');

function readJson(filePath) {
  return JSON.parse(fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, ''));
}

function check(key, ok, detail) {
  return { key, ok: Boolean(ok), detail };
}

async function main() {
  const writeReport = process.argv.includes('--write-report');
  const profile = readJson(profilePath);
  const checks = [];
  const expectedChainId = 20260718;

  checks.push(check(
    'profile_schema',
    profile.schemaVersion === 'plais-exchange-integration-profile/v1'
      && profile.profileStatus === 'TEMPLATE_EXCHANGE_TO_CONFIRM',
    'Exchange-neutral configuration template uses the controlled v1 schema.'
  ));
  checks.push(check(
    'network_identity',
    Number(profile.network?.chainId) === expectedChainId
      && profile.network?.consensus === 'QBFT'
      && profile.network?.nativeAsset?.symbol === 'PLAIS'
      && Number(profile.network?.nativeAsset?.decimals) === 18,
    'Profile declares chain ID 20260718, QBFT, PLAIS, and 18 decimals.'
  ));
  checks.push(check(
    'exchange_values_uncommitted',
    profile.endpoints?.rpcHttps === 'EXCHANGE_TO_CONFIRM'
      && profile.depositPolicy?.minimumConfirmations === 'EXCHANGE_TO_CONFIRM_DURING_UAT'
      && profile.withdrawalPolicy?.hotWalletAddress === 'EXCHANGE_TO_PROVIDE',
    'Exchange-specific endpoints, confirmation policy, limits, fees, and wallets remain explicitly uncommitted.'
  ));
  checks.push(check(
    'exchange_profile_write_controls_locked',
    profile.activationControls?.publicRpcEnabled === false
      && profile.activationControls?.externalTransfersEnabled === false
      && profile.activationControls?.operatorSigningEnabled === false
      && profile.activationControls?.productionBroadcastAllowedByThisProfile === false,
    'The exchange-neutral template cannot enable RPC, transfers, signing, or production broadcast.'
  ));
  checks.push(check(
    'live_mainnet_transfer_state',
    EVM_CANDIDATE_CONFIG.externalTransfersEnabled === true,
    `Live canonical external EVM transfers are ${EVM_CANDIDATE_CONFIG.externalTransfersEnabled === true ? 'enabled' : 'disabled'}; the read-only probe still performs no broadcast.`
  ));
  checks.push(check(
    'canonical_runtime_config',
    isCanonicalBesuQbft()
      && Number(EVM_CANDIDATE_CONFIG.chainId) === expectedChainId
      && String(EVM_CANDIDATE_CONFIG.consensus).toUpperCase() === 'QBFT',
    `Canonical ledger=${CANONICAL_LEDGER_CONFIG.id}; runtime chain ID=${EVM_CANDIDATE_CONFIG.chainId}; consensus=${EVM_CANDIDATE_CONFIG.consensus}.`
  ));

  const addressFixture = '0x000000000000000000000000000000000000dEaD';
  const checksumAddress = getAddress(addressFixture);
  checks.push(check(
    'address_validation',
    isAddress(addressFixture) && checksumAddress === addressFixture && isAddress(ZeroAddress),
    'EVM address length, hexadecimal encoding, and EIP-55 checksum handling are available.'
  ));

  let live = { rpcUrl: EVM_CANDIDATE_CONFIG.rpcUrl };
  try {
    const rpc = new JsonRpcProvider(EVM_CANDIDATE_CONFIG.rpcUrl, undefined, { staticNetwork: false });
    const [network, latestBlock, zeroBalance, validators, peerCountHex] = await Promise.all([
      rpc.getNetwork(),
      rpc.getBlock('latest'),
      rpc.getBalance(ZeroAddress),
      rpc.send('qbft_getValidatorsByBlockNumber', ['latest']),
      rpc.send('net_peerCount', [])
    ]);
    const observedChainId = Number(network.chainId);
    const blockAgeSec = latestBlock ? Math.max(0, Math.floor(Date.now() / 1000) - Number(latestBlock.timestamp)) : null;
    const validatorCount = Array.isArray(validators) ? validators.length : 0;
    const peerCount = Number.parseInt(String(peerCountHex), 16);
    live = {
      observedChainId,
      latestBlockNumber: latestBlock ? Number(latestBlock.number) : null,
      latestBlockHash: latestBlock?.hash || null,
      latestBlockAgeSeconds: blockAgeSec,
      validatorCount,
      peerCount: Number.isFinite(peerCount) ? peerCount : null,
      zeroAddressBalanceWei: zeroBalance.toString()
    };
    checks.push(check('rpc_chain_identity', observedChainId === expectedChainId, `Read-only RPC reported chain ID ${observedChainId}.`));
    checks.push(check(
      'rpc_block_read',
      Boolean(latestBlock?.hash) && blockAgeSec !== null && blockAgeSec <= CANONICAL_LEDGER_CONFIG.maxBlockAgeSec,
      latestBlock ? `Read block ${latestBlock.number}; age ${blockAgeSec}s.` : 'Latest block was unavailable.'
    ));
    checks.push(check('qbft_validator_read', validatorCount === 4, `Read-only QBFT RPC reported ${validatorCount} validators.`));
    checks.push(check('balance_read', typeof zeroBalance === 'bigint', 'Read-only native balance query succeeded.'));
  } catch (error) {
    live = { error: error.code || error.message };
    checks.push(check('rpc_chain_identity', false, `Read-only RPC check failed: ${error.code || error.message}`));
    checks.push(check('rpc_block_read', false, 'Latest block could not be verified.'));
    checks.push(check('qbft_validator_read', false, 'QBFT validator set could not be verified.'));
    checks.push(check('balance_read', false, 'Read-only balance query could not be verified.'));
  }

  const failed = checks.filter((row) => !row.ok);
  const report = {
    ok: failed.length === 0,
    schemaVersion: 'plais-exchange-integration-readiness/v1',
    status: failed.length === 0 ? 'READY_FOR_EXCHANGE_UAT' : 'INTERNAL_REMEDIATION_REQUIRED',
    exchangeSelected: false,
    exchangeUatComplete: false,
    productionTransactionBroadcast: false,
    writeOperationsPerformed: false,
    scope: 'Exchange-neutral, read-only integration preflight. This is not exchange certification or listing approval.',
    profile: path.relative(projectRoot, profilePath).replace(/\\/g, '/'),
    live,
    passed: checks.length - failed.length,
    total: checks.length,
    blockers: failed.map((row) => ({ key: row.key, detail: row.detail })),
    checks,
    checkedAt: new Date().toISOString()
  };

  if (writeReport) {
    fs.mkdirSync(path.dirname(reportPath), { recursive: true });
    fs.writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
  }
  console.log(JSON.stringify(report, null, 2));
  if (!report.ok) process.exitCode = 1;
}

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