const express = require('express');
const proofLedgerService = require('../services/proofLedgerService');
const chainTransactionService = require('../services/chainTransactionService');
const nodeParticipantService = require('../services/nodeParticipantService');
const pointLedgerService = require('../services/pointLedgerService');
const blockService = require('../services/blockService');
const backupIndexService = require('../services/backupIndexService');
const callbackService = require('../services/callbackService');
const testnetService = require('../services/testnetService');
const trxCollateralService = require('../services/trxCollateralService');
const walletService = require('../services/walletService');
const ledgerMigrationService = require('../services/ledgerMigrationService');
const persistentStore = require('../services/persistentStore');
const mongoObservation = require('../services/mongoLedgerObservationAdapter');
const ledgerDbReadinessService = require('../services/ledgerDbReadinessService');
const readSwitchApprovalService = require('../services/ledgerReadSwitchApprovalService');
const readBackendSwitchService = require('../services/ledgerReadBackendSwitchService');
const readMonitorService = require('../services/ledgerMongoReadMonitorService');
const postSwitchGuardService = require('../services/ledgerMongoPostSwitchGuardService');
const rewardAuditService = require('../services/rewardAuditService');
const rewardLedgerService = require('../services/rewardLedgerService');
const rewardLiveCanaryApprovalService = require('../services/rewardLiveCanaryApprovalService');
const rewardPolicyService = require('../services/rewardPolicyService');
const rewardReadinessService = require('../services/rewardReadinessService');
const rewardReviewService = require('../services/rewardReviewService');

const router = express.Router();

const SERVICE_ORDER = ['AISFOR', 'AISTALK', 'AISGROUP', 'AISMALL'];
const SERVICE_WALLET_NAMES = [...SERVICE_ORDER, 'AISFOR_CHAIN'];

function normalizeService(value) {
  const normalized = String(value || '').trim().toUpperCase();
  return normalized || 'ALL';
}

function sortServices(a, b) {
  const ai = SERVICE_ORDER.indexOf(a);
  const bi = SERVICE_ORDER.indexOf(b);
  if (ai !== -1 && bi !== -1) return ai - bi;
  if (ai !== -1) return -1;
  if (bi !== -1) return 1;
  return a.localeCompare(b);
}

function collectServices({ proofs, transactions, callbacks, serviceConfirmations }) {
  const services = new Set(SERVICE_ORDER);
  for (const row of proofs) services.add(normalizeService(row.sourceService));
  for (const row of transactions) services.add(normalizeService(row.sourceService));
  for (const row of callbacks) services.add(normalizeService(row.sourceService));
  for (const row of serviceConfirmations) services.add(normalizeService(row.serviceName));
  services.delete('ALL');
  return ['ALL', ...Array.from(services).sort(sortServices)];
}

function matchesService(row, selectedService, field = 'sourceService') {
  if (selectedService === 'ALL') return true;
  return normalizeService(row[field]) === selectedService;
}

function latestByTime(rows) {
  return rows.slice().sort((a, b) => {
    const at = new Date(a.confirmedAt || a.createdAt || a.updatedAt || 0).getTime();
    const bt = new Date(b.confirmedAt || b.createdAt || b.updatedAt || 0).getTime();
    return bt - at;
  })[0] || null;
}

const ONLINE_NODE_WINDOW_MS = Number(process.env.PLAIS_NODE_ONLINE_WINDOW_MS || 10 * 60 * 1000);

function isOnlineNode(node, now = Date.now()) {
  const status = String((node && node.status) || '').toLowerCase();
  if (!['active', 'warning'].includes(status)) return false;
  if (!(node && node.lastHeartbeatAt)) return false;

  const lastHeartbeatMs = new Date(node.lastHeartbeatAt).getTime();
  return Number.isFinite(lastHeartbeatMs) && now - lastHeartbeatMs <= ONLINE_NODE_WINDOW_MS;
}

function getAdminNodeStats(nodes = []) {
  const now = Date.now();
  const online = nodes.filter((node) => isOnlineNode(node, now)).length;
  return {
    total: nodes.length,
    online,
    windowMinutes: Math.round(ONLINE_NODE_WINDOW_MS / 60000)
  };
}

function buildServiceMonitorRows({ proofs, transactions, callbacks, serviceConfirmations, services }) {
  return services.filter((name) => name !== 'ALL').map((serviceName) => {
    const serviceProofs = proofs.filter((row) => matchesService(row, serviceName));
    const serviceTx = transactions.filter((row) => matchesService(row, serviceName));
    const serviceCallbacks = callbacks.filter((row) => matchesService(row, serviceName));
    const confirmation = serviceConfirmations.find((row) => normalizeService(row.serviceName) === serviceName);
    const latestProof = latestByTime(serviceProofs);
    const latestTx = latestByTime(serviceTx);
    const latestCallback = latestByTime(serviceCallbacks);
    const status = confirmation && confirmation.chainConfirmed ? 'confirmed' : (confirmation ? 'waiting' : 'no_signal');

    return {
      serviceName,
      status,
      proofCount: serviceProofs.length,
      txCount: serviceTx.length,
      callbackCount: serviceCallbacks.length,
      confirmedCallbacks: serviceCallbacks.filter((row) => row.status === 'delivered' || row.status === 'confirmed').length,
      blockHeight: confirmation?.blockHeight || latestTx?.blockHeight || latestCallback?.blockHeight || '-',
      txHash: confirmation?.txHash || latestTx?.txHash || '-',
      latestProofType: latestProof?.proofType || latestTx?.actionType || '-',
      latestAt: confirmation?.confirmedAt || latestProof?.createdAt || latestTx?.createdAt || latestCallback?.createdAt || null,
      lastError: confirmation?.lastError || latestCallback?.lastError || ''
    };
  });
}




router.post('/wallet/user', (req, res, next) => {
  try {
    const result = walletService.ensureUserWallet({
      userId: req.body.userId,
      label: req.body.label || `plais User ${req.body.userId}`,
      faucetAmount: req.body.faucetAmount || 0,
      metadata: {
        adminCreated: true,
        note: req.body.note || ''
      }
    });
    res.redirect(`/explorer/address/${encodeURIComponent(result.wallet.address)}`);
  } catch (err) {
    next(err);
  }
});
router.post('/wallet/service-sync', (req, res, next) => {
  try {
    walletService.ensureServiceWallets(SERVICE_WALLET_NAMES);
    res.redirect('/admin');
  } catch (err) {
    next(err);
  }
});

router.post('/wallet/transfer', (req, res, next) => {
  try {
    const transaction = walletService.transfer({
      fromAddress: req.body.fromAddress,
      toAddress: req.body.toAddress,
      amount: req.body.amount,
      fee: req.body.fee || 0,
      memo: req.body.memo || 'Admin wallet transfer'
    });
    res.redirect(`/explorer/tx/${encodeURIComponent(transaction.txHash)}`);
  } catch (err) {
    next(err);
  }
});
router.post('/wallet/create', (req, res, next) => {
  try {
    const wallet = walletService.createWallet({
      label: req.body.label || 'Admin Test Wallet',
      ownerType: 'test_user',
      ownerId: req.body.ownerId || 'admin-test',
      faucetAmount: req.body.faucetAmount || 1000,
      memo: 'Admin created test wallet'
    });
    res.redirect(`/explorer/address/${encodeURIComponent(wallet.address)}`);
  } catch (err) {
    next(err);
  }
});

router.post('/collateral/trx/config', (req, res, next) => {
  try {
    trxCollateralService.updateConfig({
      trxPerTb: req.body.trxPerTb,
      minimumCapacityTb: req.body.minimumCapacityTb || 1,
      updatedBy: req.session?.user?.userid || req.session?.userid || req.session?.userId || 'admin'
    });
    res.redirect('/admin?trxCollateralConfig=updated');
  } catch (err) {
    next(err);
  }
});

router.post('/collateral/trx/:eventId/confirm', (req, res, next) => {
  try {
    trxCollateralService.confirmDeposit(req.params.eventId, {
      confirmedBy: req.session?.user?.userid || req.session?.userid || req.session?.userId || 'admin',
      externalTxHash: req.body.externalTxHash
    });
    res.redirect('/admin?trxCollateral=confirmed');
  } catch (err) {
    next(err);
  }
});

router.post('/collateral/trx/:eventId/reject', (req, res, next) => {
  try {
    trxCollateralService.rejectDeposit(req.params.eventId, {
      rejectedBy: req.session?.user?.userid || req.session?.userid || req.session?.userId || 'admin',
      reason: req.body.reason || 'admin rejected'
    });
    res.redirect('/admin?trxCollateral=rejected');
  } catch (err) {
    next(err);
  }
});

router.post('/reward/simulate', (req, res, next) => {
  try {
    rewardLedgerService.createSimulationEntry({
      actorId: req.body.actorId || 'admin-simulated-user',
      sourceService: req.body.sourceService || 'AISFOR_CHAIN',
      category: req.body.category || 'ecosystem',
      actionType: req.body.actionType || 'ADMIN_REWARD_SIMULATION',
      serviceScore: req.body.serviceScore || 0,
      contentScore: req.body.contentScore || 0,
      storageScore: req.body.storageScore || 0,
      uptimeScore: req.body.uptimeScore || 0,
      verificationScore: req.body.verificationScore || 0,
      commerceScore: req.body.commerceScore || 0,
      emoticonScore: req.body.emoticonScore || 0,
      ecosystemScore: req.body.ecosystemScore || 0,
      note: req.body.note || 'Admin reward simulation'
    });
    res.redirect(req.body.returnTo === 'rewards' ? '/admin/rewards?reward=simulated' : '/admin?reward=simulated');
  } catch (err) {
    next(err);
  }
});
router.post('/rewards/simulate-policy', (req, res, next) => {
  try {
    const payload = rewardPolicyService.buildSimulationPayload({
      actorId: req.body.actorId,
      sourceService: req.body.sourceService,
      category: req.body.category,
      actionType: req.body.actionType,
      baseScore: req.body.baseScore,
      note: req.body.note,
      flags: {
        refund: req.body.refund === '1',
        cancelled: req.body.cancelled === '1',
        selfTrade: req.body.selfTrade === '1'
      }
    });
    rewardLedgerService.createSimulationEntry(payload);
    res.redirect('/admin/rewards?policyReward=simulated');
  } catch (err) {
    next(err);
  }
});
router.post('/rewards/:rewardId/review', async (req, res, next) => {
  try {
    const decision = await rewardReviewService.recordDecision({
      rewardId: req.params.rewardId,
      decision: req.body.decision,
      reviewer: req.body.reviewer || req.session?.user?.userid || req.session?.userid || req.session?.userId || 'admin',
      reason: req.body.reason || ''
    });
    res.redirect(decision.txHash ? `/explorer/tx/${encodeURIComponent(decision.txHash)}` : '/admin/rewards?review=recorded');
  } catch (err) {
    next(err);
  }
});
router.post('/rewards/review-anchors/repair', async (req, res, next) => {
  try {
    await rewardReviewService.repairAnchors({
      limit: req.body.limit || 25,
      reviewer: req.body.reviewer || req.session?.user?.userid || req.session?.userid || req.session?.userId || 'admin-anchor-repair'
    });
    res.redirect('/admin/rewards?reviewAnchorRepair=done');
  } catch (err) {
    next(err);
  }
});
router.post('/rewards/live-canary/approve', (req, res, next) => {
  try {
    const actor = req.session?.user?.userid || req.session?.userid || req.session?.userId || 'admin';
    rewardLiveCanaryApprovalService.approve({
      approvedBy: actor,
      reason: 'admin reward live canary approval'
    });
    res.redirect('/admin/rewards?liveCanaryApproval=approved');
  } catch (err) {
    next(err);
  }
});
router.post('/rewards/live-canary/revoke', (req, res, next) => {
  try {
    const actor = req.session?.user?.userid || req.session?.userid || req.session?.userId || 'admin';
    rewardLiveCanaryApprovalService.revoke({
      revokedBy: actor,
      reason: 'admin reward live canary revoke'
    });
    res.redirect('/admin/rewards?liveCanaryApproval=revoked');
  } catch (err) {
    next(err);
  }
});
router.post('/ledger-migration/dry-run', (req, res, next) => {
  try {
    ledgerMigrationService.buildDryRun({ persist: true });
    res.redirect('/admin/ledger-migration?dryRun=1');
  } catch (err) {
    next(err);
  }
});
router.post('/ledger-migration/observation-compare', async (req, res, next) => {
  try {
    const state = persistentStore.readState();
    await mongoObservation.compareState(state);
    res.redirect('/admin/ledger-migration?observation=1');
  } catch (err) {
    next(err);
  }
});
router.post('/ledger-migration/read-monitor/sample', async (req, res, next) => {
  try {
    await readMonitorService.runSample({ reason: 'admin-read-monitor-sample' });
    res.redirect('/admin/ledger-migration?readMonitor=sampled');
  } catch (err) {
    next(err);
  }
});
router.post('/ledger-migration/post-switch-guard/run', async (req, res, next) => {
  try {
    await postSwitchGuardService.runGuard({ reason: 'admin-post-switch-guard', actor: req.session?.user?.userid || req.session?.userid || req.session?.userId || 'admin' });
    res.redirect('/admin/ledger-migration?postSwitchGuard=checked');
  } catch (err) {
    next(err);
  }
});
router.post('/ledger-migration/read-switch/approve', (req, res, next) => {
  try {
    const status = ledgerDbReadinessService.getStatus();
    if (!status.readSwitchPreflightOk) {
      return res.redirect('/admin/ledger-migration?readSwitchApproval=blocked');
    }

    const actor = req.session?.user?.userid || req.session?.userid || req.session?.userId || 'admin';
    readSwitchApprovalService.approve({
      targetBackend: status.targetBackend,
      approvedBy: actor,
      reason: 'admin ledger migration approval'
    });
    return res.redirect('/admin/ledger-migration?readSwitchApproval=approved');
  } catch (err) {
    next(err);
  }
});

router.post('/ledger-migration/read-switch/revoke', (req, res, next) => {
  try {
    const actor = req.session?.user?.userid || req.session?.userid || req.session?.userId || 'admin';
    readSwitchApprovalService.revoke({
      revokedBy: actor,
      reason: 'admin ledger migration revoke'
    });
    return res.redirect('/admin/ledger-migration?readSwitchApproval=revoked');
  } catch (err) {
    next(err);
  }
});
router.post('/ledger-migration/read-backend/request-mongo', (req, res, next) => {
  try {
    const status = ledgerDbReadinessService.getStatus();
    if (!status.readSwitchPreflightOk) {
      return res.redirect('/admin/ledger-migration?readBackend=blocked');
    }

    const actor = req.session?.user?.userid || req.session?.userid || req.session?.userId || 'admin';
    readSwitchApprovalService.approve({
      targetBackend: status.targetBackend,
      approvedBy: actor,
      reason: 'admin requested Mongo read backend'
    });
    readBackendSwitchService.setReadBackend('mongodb', {
      actor,
      reason: 'admin requested Mongo read backend'
    });
    return res.redirect('/admin/ledger-migration?readBackend=mongodb-requested');
  } catch (err) {
    next(err);
  }
});

router.post('/ledger-migration/read-backend/rollback-json', (req, res, next) => {
  try {
    const actor = req.session?.user?.userid || req.session?.userid || req.session?.userId || 'admin';
    readBackendSwitchService.setReadBackend('json-file', {
      actor,
      reason: 'admin rollback to JSON read backend'
    });
    readSwitchApprovalService.revoke({
      revokedBy: actor,
      reason: 'admin rollback to JSON read backend'
    });
    return res.redirect('/admin/ledger-migration?readBackend=json-rollback');
  } catch (err) {
    next(err);
  }
});
router.get('/ledger-migration', (req, res) => {
  res.render('ledger-migration', {
    service: {
      name: 'plais Chain',
      mode: 'Ledger DB Migration Prep',
      port: process.env.PORT || 4317
    },
    migration: ledgerMigrationService.getStatus()
  });
});
router.get('/rewards', (req, res) => {
  res.render('admin_rewards', {
    service: {
      name: 'plais Chain',
      mode: 'PoSS Reward Simulation',
      port: process.env.PORT || 4317
    },
    rewardStats: rewardLedgerService.getStats(),
    rewardAuditStats: rewardAuditService.getStats(),
    rewardReviewQueue: rewardLedgerService.getReviewQueue(),
    rewardReviewStats: rewardReviewService.getStats(),
    rewardReadiness: rewardReadinessService.getStatus(),
    rewardLiveCanaryApproval: rewardLiveCanaryApprovalService.getApproval(),
    rewardManifest: rewardPolicyService.getIntegrationManifest(),
    rewardPolicy: rewardPolicyService.getPolicy(),
    testnetStatus: testnetService.getStatus()
  });
});
router.get('/', (req, res) => {
  const proofs = proofLedgerService.listProofs();
  const transactions = chainTransactionService.listTransactions();
  const callbacks = callbackService.listCallbacks();
  const serviceConfirmations = callbackService.getServiceConfirmationRows();
  const serviceOptions = collectServices({ proofs, transactions, callbacks, serviceConfirmations });
  const requestedService = normalizeService(req.query.service);
  const selectedService = serviceOptions.includes(requestedService) ? requestedService : 'ALL';
  const filteredProofs = proofs.filter((row) => matchesService(row, selectedService));
  const filteredTransactions = transactions.filter((row) => matchesService(row, selectedService));
  const filteredCallbacks = callbacks.filter((row) => matchesService(row, selectedService));
  const filteredServiceConfirmations = serviceConfirmations.filter((row) => matchesService(row, selectedService, 'serviceName'));
  const serviceWallets = walletService.ensureServiceWallets(SERVICE_WALLET_NAMES);
  const userWallets = walletService.listUserWallets();
  const nodes = nodeParticipantService.listNodes();
  const adminNodeStats = getAdminNodeStats(nodes);

  res.render('admin', {
    service: {
      name: 'plais Chain',
      mode: 'Mock plais Mainnet',
      port: process.env.PORT || 4317
    },
    selectedService,
    serviceOptions,
    serviceMonitorRows: buildServiceMonitorRows({ proofs, transactions, callbacks, serviceConfirmations, services: serviceOptions }),
    testnetStatus: testnetService.getStatus(),
    proofs,
    filteredProofs,
    proofStats: proofLedgerService.getProofStats(),
    transactions,
    filteredTransactions,
    blocks: blockService.listBlocks(),
    blockStats: blockService.getBlockStats(),
    blockChain: blockService.verifyBlockChain(),
    callbacks,
    filteredCallbacks,
    callbackStats: callbackService.getCallbackStats(),
    serviceConfirmations,
    filteredServiceConfirmations,
    nodes,
    adminNodeStats,
    nodeEconomyEntries: nodeParticipantService.listEconomyEntries(),
    nodeEconomyStats: nodeParticipantService.getEconomyStats(),
    pointEntries: pointLedgerService.listEntries(),
    backupIndexes: backupIndexService.listBackups(),
    distributedChunks: backupIndexService.listChunks(),
    backupStats: backupIndexService.getBackupStats(),
    walletStats: walletService.getStats(),
    wallets: walletService.listWallets(),
    walletTransactions: walletService.listWalletTransactions(),
    serviceWallets,
    userWallets,
    trxCollateralStats: trxCollateralService.getStats(),
    trxCollateralAccounts: trxCollateralService.listAccounts(),
    trxCollateralEvents: trxCollateralService.listEvents({ limit: 20 }),
    rewardStats: rewardLedgerService.getStats(),
    ledgerMigration: ledgerMigrationService.getStatus()
  });
});

module.exports = router;
