const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const blockService = require('./blockService');
const rewardAuditService = require('./rewardAuditService');
const rewardLedgerService = require('./rewardLedgerService');
const rewardLiveCanaryPostCheckService = require('./rewardLiveCanaryPostCheckService');
const rewardPolicyService = require('./rewardPolicyService');
const rewardReviewService = require('./rewardReviewService');
const {
  SERVICE_ENV_KEYS,
  getConfiguredServices,
  isAuthRequired
} = require('../config/serviceCredentials');

function checkItem(key, label, ok, detail, severity = 'medium') {
  return {
    key,
    label,
    ok: Boolean(ok),
    severity,
    status: ok ? 'OK' : 'WATCH',
    detail
  };
}

function getSourceReadiness(policy) {
  const configuredServices = new Set(getConfiguredServices());
  return policy.sources.map((source) => {
    const connected = ['connected', 'internal'].includes(source.status);
    const ready = connected || source.status === 'ready_for_client_integration';
    const authRequired = isAuthRequired();
    const authConfigured = source.serviceName === 'AISFOR_CHAIN'
      ? true
      : configuredServices.has(source.serviceName);
    return {
      serviceName: source.serviceName,
      status: source.status,
      ready,
      connected,
      authRequired,
      authConfigured,
      authEnvKey: SERVICE_ENV_KEYS[source.serviceName] || 'internal',
      categories: source.categories,
      eventTypes: source.eventTypes,
      endpoint: source.endpoint,
      idempotency: source.idempotency,
      note: source.note
    };
  });
}

function readLatestHttpSmoke() {
  const smokePath = path.join(__dirname, '..', 'data', 'reward-http-dry-run-smoke.json');
  if (!fs.existsSync(smokePath)) {
    return {
      ok: false,
      totalServices: 0,
      passedServices: 0,
      reviewServices: 0,
      checkedAt: null,
      detail: 'no smoke result yet'
    };
  }

  try {
    return JSON.parse(fs.readFileSync(smokePath, 'utf8'));
  } catch (err) {
    return {
      ok: false,
      totalServices: 0,
      passedServices: 0,
      reviewServices: 0,
      checkedAt: null,
      detail: `smoke result parse failed: ${err.message}`
    };
  }
}

function readLatestLiveCanary() {
  const canaryPath = path.join(__dirname, '..', 'data', 'reward-live-canary.json');
  if (!fs.existsSync(canaryPath)) {
    return {
      ok: false,
      live: false,
      mode: 'not-run',
      serviceName: '',
      checkedAt: null,
      detail: 'no live canary result yet'
    };
  }

  try {
    return JSON.parse(fs.readFileSync(canaryPath, 'utf8'));
  } catch (err) {
    return {
      ok: false,
      live: false,
      mode: 'parse-failed',
      serviceName: '',
      checkedAt: null,
      detail: `live canary result parse failed: ${err.message}`
    };
  }
}

function buildRolloutPlan({ sourceReadiness = [], latestHttpSmoke = {} } = {}) {
  const smokeRows = new Map((latestHttpSmoke.rows || []).map((row) => [row.serviceName, row]));
  return sourceReadiness
    .filter((source) => source.serviceName !== 'AISFOR_CHAIN')
    .map((source) => {
      const smoke = smokeRows.get(source.serviceName) || null;
      const smokeOk = Boolean(smoke && smoke.ok);
      const readyForLiveSimulation = Boolean(source.authConfigured && smokeOk);
      const status = source.connected
        ? 'CONNECTED'
        : (readyForLiveSimulation ? 'READY_FOR_LIVE_SIMULATION' : 'WAITING_FOR_SERVICE_WIRING');
      const nextAction = source.connected
        ? 'Monitor live mirrored reward events and review queue.'
        : (readyForLiveSimulation
          ? 'Wire this service to submit real events through dry-run first, then controlled live simulation writes.'
          : 'Configure service credential and pass HTTP dry-run smoke.');

      return {
        serviceName: source.serviceName,
        status,
        sourceStatus: source.status,
        authConfigured: source.authConfigured,
        dryRunSmokeOk: smokeOk,
        wouldNeedReview: Boolean(smoke?.wouldNeedReview),
        rewardAmount: Number(smoke?.rewardAmount || 0),
        flags: smoke?.flags || [],
        nextAction
      };
    });
}

function buildLiveCanaryPreflight({ readinessStatus = '', readinessScore = 0, latestHttpSmoke = {}, latestLiveCanary = {}, rolloutPlan = [] } = {}) {
  const connected = rolloutPlan.filter((row) => row.status === 'CONNECTED');
  const ready = rolloutPlan.filter((row) => row.status === 'READY_FOR_LIVE_SIMULATION');
  const checks = [
    checkItem(
      'readiness_ok',
      'Reward readiness OK',
      readinessStatus === 'OK' && Number(readinessScore || 0) === 100,
      `${readinessStatus || 'UNKNOWN'} / ${readinessScore || 0}%`,
      'high'
    ),
    checkItem(
      'http_smoke_ok',
      'HTTP dry-run smoke OK',
      latestHttpSmoke.ok && Number(latestHttpSmoke.passedServices || 0) >= 1,
      `${latestHttpSmoke.passedServices || 0}/${latestHttpSmoke.totalServices || 0} services passed`,
      'high'
    ),
    checkItem(
      'dry_canary_ok',
      'Dry-run canary OK',
      latestLiveCanary.ok && latestLiveCanary.live === false,
      `${latestLiveCanary.mode || 'not-run'} / ${latestLiveCanary.serviceName || '-'}`,
      'high'
    ),
    checkItem(
      'rollout_target_available',
      'Rollout target available',
      connected.length > 0 || ready.length > 0,
      `${connected.length} connected, ${ready.length} ready`,
      'medium'
    )
  ];
  const failed = checks.filter((row) => !row.ok);

  return {
    ok: failed.length === 0,
    status: failed.length ? 'WAIT' : 'READY',
    confirmRequiredForLive: 'LIVE_SIMULATION_WRITE',
    checks,
    failedChecks: failed,
    recommendedNextAction: failed.length
      ? 'Fix failed preflight checks, then run dry-run canary again.'
      : 'Operator may run scripts/reward-live-canary.js with --confirm=LIVE_SIMULATION_WRITE for one controlled live simulation write.'
  };
}

function buildLiveCanaryPermit({ readinessStatus = '', readinessScore = 0, latestLiveCanary = {}, liveCanaryPreflight = {}, liveCanaryPostCheck = {}, rolloutPlan = [] } = {}) {
  const connected = rolloutPlan.filter((row) => row.status === 'CONNECTED');
  const ready = rolloutPlan.filter((row) => row.status === 'READY_FOR_LIVE_SIMULATION');
  const target = connected[0] || ready[0] || null;
  const serviceName = target?.serviceName || '';
  const dryRunCommand = serviceName
    ? `node scripts\\reward-live-canary.js --service=${serviceName} --base-url=http://127.0.0.1:4317`
    : '';
  const liveCommand = serviceName
    ? `${dryRunCommand} --confirm=LIVE_SIMULATION_WRITE`
    : '';
  const checks = [
    checkItem(
      'readiness_status_ok',
      'Reward readiness status OK',
      readinessStatus === 'OK' && Number(readinessScore || 0) === 100,
      `${readinessStatus || 'UNKNOWN'} / ${readinessScore || 0}%`,
      'high'
    ),
    checkItem(
      'preflight_ready',
      'Live canary preflight ready',
      liveCanaryPreflight.ok,
      liveCanaryPreflight.status || 'WAIT',
      'high'
    ),
    checkItem(
      'postcheck_clean',
      'Previous canary post-check clean',
      liveCanaryPostCheck.ok,
      `${liveCanaryPostCheck.canaryMode || 'not-run'} / ${liveCanaryPostCheck.live ? 'live' : 'dry-run'}`,
      'high'
    ),
    checkItem(
      'latest_canary_is_dry_run',
      'Latest canary is dry-run',
      latestLiveCanary.ok && latestLiveCanary.live === false,
      `${latestLiveCanary.mode || 'not-run'} / ${latestLiveCanary.serviceName || '-'}`,
      'high'
    ),
    checkItem(
      'target_service_available',
      'Target service available',
      Boolean(target),
      target ? `${target.serviceName} / ${target.status}` : 'no connected or ready service',
      'high'
    )
  ];
  const failed = checks.filter((row) => !row.ok);
  const checkedAt = new Date().toISOString();
  const permitId = crypto
    .createHash('sha256')
    .update([
      serviceName,
      latestLiveCanary.idempotencyKey || '',
      liveCanaryPostCheck.idempotencyKey || '',
      checks.map((row) => `${row.key}:${row.ok ? '1' : '0'}`).join('|')
    ].join('|'))
    .digest('hex')
    .slice(0, 16);

  return {
    ok: failed.length === 0,
    status: failed.length ? 'LOCKED' : 'PERMITTED',
    mode: 'reward-live-canary-permit',
    permitId,
    serviceName,
    confirmRequiredForLive: 'LIVE_SIMULATION_WRITE',
    dryRunCommand,
    liveCommand,
    checks,
    failedChecks: failed,
    checkedAt,
    note: failed.length
      ? 'Do not run a live simulation write until all permit checks pass.'
      : 'A single controlled live simulation write is permitted after explicit operator approval.'
  };
}

function getStatus() {
  const policy = rewardPolicyService.getPolicy();
  const manifest = rewardPolicyService.getIntegrationManifest();
  const rewardStats = rewardLedgerService.getStats();
  const auditStats = rewardAuditService.getStats();
  const reviewStats = rewardReviewService.getStats();
  const blockStats = blockService.getBlockStats();
  const sourceReadiness = getSourceReadiness(policy);
  const manifestValidation = rewardPolicyService.validateIntegrationManifestSamples();
  const dryRunRows = manifest.services.flatMap((source) => (
    (source.samplePayloads || []).map((payload) => {
      const validation = rewardPolicyService.validateRewardSubmission(payload);
      const dryRun = rewardLedgerService.dryRunExternalPointReward({
        ...payload,
        sourcePolicyFlags: validation.flags,
        sourcePolicyWarnings: validation.warnings,
        sourcePolicyValidation: {
          ok: validation.ok,
          sourceService: validation.sourceService,
          category: validation.category,
          actionType: validation.actionType,
          flags: validation.flags,
          warnings: validation.warnings
        }
      });
      return {
        ok: validation.ok && dryRun.ok,
        wouldNeedReview: dryRun.wouldNeedReview
      };
    })
  ));
  const failedDryRuns = dryRunRows.filter((row) => !row.ok);
  const reviewDryRuns = dryRunRows.filter((row) => row.wouldNeedReview);
  const connectedSources = sourceReadiness.filter((row) => row.connected);
  const readySources = sourceReadiness.filter((row) => row.ready);
  const externalSources = sourceReadiness.filter((row) => row.serviceName !== 'AISFOR_CHAIN');
  const authConfiguredSources = externalSources.filter((row) => row.authConfigured);
  const latestHttpSmoke = readLatestHttpSmoke();
  const latestLiveCanary = readLatestLiveCanary();
  const liveCanaryPostCheck = rewardLiveCanaryPostCheckService.getStatus();
  const rolloutPlan = buildRolloutPlan({ sourceReadiness, latestHttpSmoke });
  const rolloutReady = rolloutPlan.filter((row) => row.status === 'READY_FOR_LIVE_SIMULATION');
  const rolloutConnected = rolloutPlan.filter((row) => row.status === 'CONNECTED');

  const checks = [
    checkItem(
      'tokenomics_guardrails',
      'Tokenomics guardrails',
      policy.settlement.simulationOnly && policy.settlement.publicIssuanceDisabled,
      `mode ${policy.settlement.currentMode}, public issuance disabled ${policy.settlement.publicIssuanceDisabled}`,
      'high'
    ),
    checkItem(
      'source_policy_defined',
      'Reward source policies',
      sourceReadiness.length >= 5 && sourceReadiness.every((row) => row.endpoint && row.idempotency),
      `${sourceReadiness.length} sources, ${connectedSources.length} connected/internal, ${readySources.length} ready`,
      'high'
    ),
    checkItem(
      'integration_manifest_samples',
      'Integration manifest samples',
      manifestValidation.ok && manifestValidation.totalSamples > 0,
      `${manifestValidation.passedSamples}/${manifestValidation.totalSamples} valid, ${manifestValidation.warningSamples} warning samples`,
      'high'
    ),
    checkItem(
      'reward_dry_run_samples',
      'Reward dry-run samples',
      failedDryRuns.length === 0 && dryRunRows.length > 0,
      `${dryRunRows.length - failedDryRuns.length}/${dryRunRows.length} accepted, ${reviewDryRuns.length} would need review`,
      'high'
    ),
    checkItem(
      'service_auth_configuration',
      'Service auth configuration',
      authConfiguredSources.length > 0 && (!isAuthRequired() || externalSources.every((row) => row.authConfigured)),
      `auth required ${isAuthRequired()}, ${authConfiguredSources.length}/${externalSources.length} external service keys configured`,
      isAuthRequired() ? 'high' : 'medium'
    ),
    checkItem(
      'reward_http_dry_run_smoke',
      'Reward HTTP dry-run smoke',
      latestHttpSmoke.ok && latestHttpSmoke.totalServices >= externalSources.length,
      `${latestHttpSmoke.passedServices || 0}/${latestHttpSmoke.totalServices || 0} services passed, ${latestHttpSmoke.reviewServices || 0} would need review`,
      'high'
    ),
    checkItem(
      'reward_ledger_present',
      'Reward ledger',
      rewardStats.entryCount > 0,
      `${rewardStats.entryCount} reward entries, ${rewardStats.totalSimulatedReward} simulated reward`,
      'medium'
    ),
    checkItem(
      'audit_log_present',
      'Reward audit log',
      auditStats.entryCount > 0,
      `${auditStats.entryCount} audit logs`,
      'medium'
    ),
    checkItem(
      'review_queue_clear',
      'Review queue',
      rewardStats.reviewCount === 0,
      `${rewardStats.reviewCount} pending, ${rewardStats.resolvedReviewCount || 0} resolved`,
      'medium'
    ),
    checkItem(
      'review_anchor_health',
      'Review anchor health',
      reviewStats.pendingAnchorCount === 0 && reviewStats.missingTxCount === 0,
      `${reviewStats.anchoredCount} anchored, ${reviewStats.pendingAnchorCount} pending anchors, ${reviewStats.missingTxCount} missing tx`,
      'high'
    ),
    checkItem(
      'block_engine',
      'Block engine',
      blockStats.totalBlocks > 0 && blockStats.finalizedBlocks > 0,
      `${blockStats.totalBlocks} blocks, ${blockStats.finalizedBlocks} finalized, ${blockStats.pendingValidationBlocks} pending validation`,
      'high'
    )
  ];

  const failed = checks.filter((row) => !row.ok);
  const highFailed = failed.filter((row) => row.severity === 'high');
  const readinessScore = Math.round(((checks.length - failed.length) / checks.length) * 100);
  const status = highFailed.length ? 'ATTENTION' : (failed.length ? 'WATCH' : 'OK');
  const liveCanaryPreflight = buildLiveCanaryPreflight({
    readinessStatus: status,
    readinessScore,
    latestHttpSmoke,
    latestLiveCanary,
    rolloutPlan
  });
  const liveCanaryPermit = buildLiveCanaryPermit({
    readinessStatus: status,
    readinessScore,
    latestLiveCanary,
    liveCanaryPreflight,
    liveCanaryPostCheck,
    rolloutPlan
  });

  return {
    ok: failed.length === 0,
    status,
    readinessScore,
    checkedAt: new Date().toISOString(),
    checks,
    failedChecks: failed,
    sourceReadiness,
    summary: {
      rewardEntries: rewardStats.entryCount,
      auditLogs: auditStats.entryCount,
      reviewQueue: rewardStats.reviewCount,
      reviewDecisions: reviewStats.decisionCount,
      anchoredReviews: reviewStats.anchoredCount,
      pendingReviewAnchors: reviewStats.pendingAnchorCount,
      missingReviewTx: reviewStats.missingTxCount,
      totalBlocks: blockStats.totalBlocks,
      finalizedBlocks: blockStats.finalizedBlocks,
      integrationSamples: manifestValidation.totalSamples,
      integrationSampleWarnings: manifestValidation.warningSamples,
      dryRunSamples: dryRunRows.length,
      dryRunReviewSamples: reviewDryRuns.length,
      httpDryRunSmokeServices: latestHttpSmoke.totalServices || 0,
      httpDryRunSmokePassed: latestHttpSmoke.passedServices || 0,
      liveCanaryOk: Boolean(latestLiveCanary.ok),
      liveCanaryLive: Boolean(latestLiveCanary.live),
      liveCanaryPreflightOk: Boolean(liveCanaryPreflight.ok),
      liveCanaryPostCheckOk: Boolean(liveCanaryPostCheck.ok),
      liveCanaryPermitOk: Boolean(liveCanaryPermit.ok),
      rolloutReadyServices: rolloutReady.length,
      rolloutConnectedServices: rolloutConnected.length,
      rolloutTotalServices: rolloutPlan.length,
      authRequired: isAuthRequired(),
      authConfiguredServices: authConfiguredSources.length,
      authExternalServices: externalSources.length
    },
    manifestValidation,
    latestHttpSmoke,
    latestLiveCanary,
    liveCanaryPreflight,
    liveCanaryPostCheck,
    liveCanaryPermit,
    rolloutPlan
  };
}

module.exports = {
  buildLiveCanaryPermit,
  buildLiveCanaryPreflight,
  buildRolloutPlan,
  getStatus
};
