const blockService = require('./blockService');
const callbackService = require('./callbackService');
const canonicalLedgerService = require('./canonicalLedgerService');
const chainTransactionService = require('./chainTransactionService');
const proofLedgerService = require('./proofLedgerService');
const assetPolicyService = require('./assetPolicyService');
const operatorCustodyService = require('./operatorCustodyService');
const { CANONICAL_LEDGER_CONFIG, isCanonicalBesuQbft } = require('../config/canonicalLedgerConfig');
const { EVM_CANDIDATE_CONFIG } = require('../config/evmCandidateConfig');

const TESTNET_CONFIG = Object.freeze({
  chainName: EVM_CANDIDATE_CONFIG.networkName,
  networkId: process.env.AISFOR_CHAIN_NETWORK_ID || `plais-qbft-${EVM_CANDIDATE_CONFIG.chainId}`,
  nativeSymbol: EVM_CANDIDATE_CONFIG.currencySymbol,
  canonicalLedger: CANONICAL_LEDGER_CONFIG.id,
  canonicalRole: CANONICAL_LEDGER_CONFIG.role,
  legacyLedgerRole: CANONICAL_LEDGER_CONFIG.legacyRole,
  rpcMode: 'besu-json-rpc',
  consensus: EVM_CANDIDATE_CONFIG.consensus,
  chainId: EVM_CANDIDATE_CONFIG.chainId,
  blockTimeTargetSec: CANONICAL_LEDGER_CONFIG.blockTimeTargetSec,
  externalWallet: EVM_CANDIDATE_CONFIG.externalTransfersEnabled ? 'user-send-enabled' : 'candidate-locked',
  faucet: 'disabled'
});

function getValidators() {
  return canonicalLedgerService.getValidators();
}

function getLegacyValidators() {
  return blockService.getEligibleValidators().map((node) => ({
    nodeId: node.nodeId,
    displayName: node.deviceName || node.serviceName || node.nodeId,
    status: node.status,
    role: node.role,
    lockedPoint: node.lockedPoint || 0,
    canonical: false
  }));
}

function getGenesisPreview() {
  const canonical = canonicalLedgerService.getStatus();
  return {
    chainName: TESTNET_CONFIG.chainName,
    networkId: TESTNET_CONFIG.networkId,
    chainId: TESTNET_CONFIG.chainId,
    consensus: TESTNET_CONFIG.consensus,
    genesisHash: canonical.genesisHash || '',
    validatorCount: canonical.validatorCount || 0,
    canonicalLedger: TESTNET_CONFIG.canonicalLedger,
    note: 'Genesis identity is read from the canonical Besu QBFT RPC. Legacy mock genesis is not canonical.'
  };
}

function countConfirmedCallbacks(callbacks) {
  return callbacks.filter((row) => {
    const status = String(row.status || '').toUpperCase();
    return status === 'DELIVERED' || status === 'MOCK_DELIVERED' || status === 'CONFIRMED';
  }).length;
}

function getReadiness() {
  const canonical = canonicalLedgerService.getStatus();
  const legacyStats = blockService.getBlockStats();
  const legacyVerify = blockService.verifyBlockChain();
  const callbacks = callbackService.listCallbacks();
  const serviceConfirmations = callbackService.getServiceConfirmationRows();
  const proofs = proofLedgerService.listProofs();
  const transactions = chainTransactionService.listTransactions();
  const latestAge = canonical.latestBlockAgeSec === null || canonical.latestBlockAgeSec === undefined
    ? Number.NaN
    : Number(canonical.latestBlockAgeSec);
  const assetPolicy = assetPolicyService.getStatus();
  const operatorCustody = operatorCustodyService.getStatus();
  const checks = [
    {
      key: 'canonical_ledger_selection',
      label: 'Besu QBFT is the canonical ledger',
      ok: isCanonicalBesuQbft(),
      detail: `${CANONICAL_LEDGER_CONFIG.id} / ${CANONICAL_LEDGER_CONFIG.role}.`
    },
    {
      key: 'canonical_rpc',
      label: 'Canonical QBFT RPC is online',
      ok: canonical.online === true,
      detail: canonical.online ? `Block #${canonical.blockNumber}.` : (canonical.error || 'RPC unavailable.')
    },
    {
      key: 'canonical_chain_id',
      label: 'Canonical chain ID matches policy',
      ok: canonical.chainId === EVM_CANDIDATE_CONFIG.chainId,
      detail: `${canonical.chainId || 'unknown'} / expected ${EVM_CANDIDATE_CONFIG.chainId}.`
    },
    {
      key: 'canonical_consensus',
      label: 'Canonical consensus is QBFT',
      ok: String(canonical.consensus || '').toUpperCase() === 'QBFT',
      detail: String(canonical.consensus || 'unknown').toUpperCase()
    },
    {
      key: 'canonical_validator_quorum',
      label: 'Canonical validator quorum is complete',
      ok: Number(canonical.validatorCount || 0) >= EVM_CANDIDATE_CONFIG.validatorCount,
      detail: `${canonical.validatorCount || 0}/${EVM_CANDIDATE_CONFIG.validatorCount} validator(s).`
    },
    {
      key: 'canonical_peer_connectivity',
      label: 'Canonical RPC sees validator peers',
      ok: Number(canonical.peerCount || 0) >= EVM_CANDIDATE_CONFIG.validatorCount,
      detail: `${canonical.peerCount || 0} peer(s).`
    },
    {
      key: 'canonical_block_liveness',
      label: 'Canonical blocks are live',
      ok: Number.isFinite(latestAge) && latestAge <= CANONICAL_LEDGER_CONFIG.maxBlockAgeSec,
      detail: Number.isFinite(latestAge)
        ? `Latest block age ${latestAge}s; limit ${CANONICAL_LEDGER_CONFIG.maxBlockAgeSec}s.`
        : 'Latest block age is unavailable.'
    },
    {
      key: 'validator_host_distribution',
      label: 'Validators are on independent hosts',
      ok: canonical.hostEvidenceComplete === true
        && Number(canonical.independentValidatorHostCount || 0) >= CANONICAL_LEDGER_CONFIG.requiredIndependentHosts,
      detail: `${canonical.independentValidatorHostCount || 0}/${CANONICAL_LEDGER_CONFIG.requiredIndependentHosts} independent host(s), ${canonical.validatorPeerIdentityCount || 0} validator peer identity match(es).`
    },
    {
      key: 'external_transfer_status',
      label: 'Canonical wallet external transfers are enabled',
      ok: canonical.externalTransfersEnabled === true,
      detail: canonical.externalTransfersEnabled ? 'Authenticated owner-signed transfers are enabled.' : 'External transfers are locked.'
    },
    {
      key: 'operator_key_custody',
      label: 'Operator key is isolated from the web service',
      ok: operatorCustody.ok === true,
      detail: `${operatorCustody.checks.filter((check) => check.ok).length}/${operatorCustody.checks.length} custody control(s) active.`
    },
    {
      key: 'canonical_asset_genesis_supply',
      label: 'Canonical native asset matches genesis allocation',
      ok: assetPolicy.checks.find((check) => check.key === 'canonical_asset_genesis_supply')?.ok === true,
      detail: assetPolicy.checks.find((check) => check.key === 'canonical_asset_genesis_supply')?.detail || 'Asset check unavailable.'
    },
    {
      key: 'canonical_asset_identity',
      label: 'Canonical symbol and decimal policy are fixed',
      ok: assetPolicy.checks.find((check) => check.key === 'canonical_asset_identity')?.ok === true,
      detail: assetPolicy.checks.find((check) => check.key === 'canonical_asset_identity')?.detail || 'Asset check unavailable.'
    },
    {
      key: 'legacy_point_separation',
      label: 'Legacy application points are separated from canonical coin',
      ok: assetPolicy.checks.find((check) => check.key === 'legacy_point_separation')?.ok === true,
      detail: assetPolicy.checks.find((check) => check.key === 'legacy_point_separation')?.detail || 'Asset check unavailable.'
    },
    {
      key: 'asset_policy_locks',
      label: 'Issuance and legacy asset safeguards are active',
      ok: assetPolicy.checks.find((check) => check.key === 'asset_policy_locks')?.ok === true,
      detail: assetPolicy.checks.find((check) => check.key === 'asset_policy_locks')?.detail || 'Asset check unavailable.'
    },
    {
      key: 'token_distribution_policy',
      label: 'Token distribution totals and TGE ceiling are internally consistent',
      ok: assetPolicy.checks.find((check) => check.key === 'token_distribution_policy')?.ok === true,
      detail: assetPolicy.checks.find((check) => check.key === 'token_distribution_policy')?.detail || 'Distribution check unavailable.'
    },
    {
      key: 'legacy_mock_block_lock',
      label: 'Legacy mock ledger is read-only',
      ok: process.env.AISFOR_CHAIN_MOCK_BLOCK_WRITES_ENABLED === '0',
      detail: process.env.AISFOR_CHAIN_MOCK_BLOCK_WRITES_ENABLED === '0'
        ? 'Legacy mining, voting, and finalization are locked.'
        : 'Legacy mock writes are enabled.'
    },
    {
      key: 'legacy_archive_integrity',
      label: 'Legacy archive hash chain verifies',
      ok: legacyVerify.ok === true,
      detail: `${legacyVerify.checked || 0} archived block(s) checked.`
    },
    {
      key: 'legacy_archive_isolation',
      label: 'Legacy finality is isolated from canonical readiness',
      ok: Number(legacyStats.pendingValidationBlocks || 0) === 0,
      detail: `${legacyStats.archivedLegacyBlocks || 0} archived, ${legacyStats.quarantinedLegacyBlocks || 0} quarantined, ${legacyStats.pendingValidationBlocks || 0} pending.`
    },
    {
      key: 'service_confirmations',
      label: 'Application service confirmations are visible',
      ok: serviceConfirmations.some((row) => row.chainConfirmed),
      detail: `${serviceConfirmations.filter((row) => row.chainConfirmed).length}/${serviceConfirmations.length} confirmation row(s).`
    },
    {
      key: 'callbacks',
      label: 'Application callback history is preserved',
      ok: countConfirmedCallbacks(callbacks) > 0,
      detail: `${countConfirmedCallbacks(callbacks)}/${callbacks.length} callback(s) delivered.`
    },
    {
      key: 'proof_tx_archive',
      label: 'Application proof and transaction history is preserved',
      ok: proofs.length > 0 && transactions.length > 0,
      detail: `${proofs.length} proof(s), ${transactions.length} transaction(s).`
    }
  ];
  const passed = checks.filter((check) => check.ok).length;
  const score = Math.round((passed / checks.length) * 100);
  return {
    status: score === 100 ? 'ready_candidate_network' : 'hardening_candidate_network',
    score,
    passed,
    total: checks.length,
    checks
  };
}

function buildStatus() {
  const canonical = canonicalLedgerService.getStatus();
  const legacyStats = blockService.getBlockStats();
  const canonicalHeight = Number(canonical.blockNumber || 0);
  const assetPolicy = assetPolicyService.getStatus();
  return {
    config: TESTNET_CONFIG,
    canonical,
    coin: assetPolicy.canonical,
    assetPolicy,
    readiness: getReadiness(),
    genesis: getGenesisPreview(),
    validators: getValidators(),
    latestBlock: canonical.latestBlockHash ? {
      height: canonicalHeight,
      number: canonicalHeight,
      blockHash: canonical.latestBlockHash,
      hash: canonical.latestBlockHash,
      createdAt: canonical.latestBlockTimestamp,
      status: 'FINALIZED_QBFT'
    } : null,
    blockStats: {
      totalBlocks: canonicalHeight + 1,
      latestHeight: canonicalHeight,
      finalizedBlocks: canonicalHeight + 1,
      pendingValidationBlocks: 0,
      validatorCount: canonical.validatorCount || 0,
      peerCount: canonical.peerCount || 0
    },
    chainVerify: {
      ok: canonical.online === true,
      mode: 'besu-qbft-rpc',
      chainId: canonical.chainId,
      latestBlockHash: canonical.latestBlockHash || '',
      checkedAt: canonical.checkedAt || null
    },
    legacyArchive: {
      role: CANONICAL_LEDGER_CONFIG.legacyRole,
      readOnly: process.env.AISFOR_CHAIN_MOCK_BLOCK_WRITES_ENABLED === '0',
      blockStats: legacyStats,
      chainVerify: blockService.verifyBlockChain(),
      validators: getLegacyValidators()
    }
  };
}

function getStatus() {
  return buildStatus();
}

async function refreshStatus() {
  await canonicalLedgerService.refreshStatus();
  return buildStatus();
}

function startCanonicalStatusMonitor() {
  return canonicalLedgerService.startMonitor();
}

module.exports = {
  TESTNET_CONFIG,
  getGenesisPreview,
  getLegacyValidators,
  getReadiness,
  getStatus,
  getValidators,
  refreshStatus,
  startCanonicalStatusMonitor
};
