const RewardReviewDecision = require('../models/RewardReviewDecision');
const blockService = require('./blockService');
const chainTransactionService = require('./chainTransactionService');
const persistentStore = require('./persistentStore');

const ALLOWED_DECISIONS = new Set(['APPROVE', 'WATCH', 'REJECT']);

function getState() {
  return persistentStore.readState();
}

function listDecisions() {
  return Array.isArray(getState().rewardReviewDecisions) ? getState().rewardReviewDecisions : [];
}

function getDecisionForReward(rewardId) {
  const key = String(rewardId || '').trim();
  if (!key) return null;
  return listDecisions().find((row) => row.rewardId === key) || null;
}

function buildReviewTransactionPayload(row, reward = {}) {
  return {
    sourceService: 'AISFOR_CHAIN',
    actionType: 'REWARD_REVIEW_DECISION',
    actorId: row.reviewer,
    targetId: row.rewardId,
    amount: 0,
    metadata: {
      reviewDecisionId: row.id,
      rewardId: row.rewardId,
      decision: row.decision,
      reason: row.reason,
      previousRewardAmount: row.previousRewardAmount,
      flags: row.flags || reward.flags || []
    }
  };
}

function attachTransaction(row, transaction) {
  row.chainTransactionId = transaction.id;
  row.txHash = transaction.txHash;
  row.chainNetworkId = transaction.networkId;
  row.chainStatus = transaction.status;
  row.chainMockBlockHeight = transaction.blockHeight || null;
  row.confirmedAt = transaction.confirmedAt || null;
}

function attachLedgerAnchor(row, transaction, mined = null) {
  row.chainLedgerBlockId = transaction.blockId || null;
  row.chainLedgerBlockHeight = transaction.ledgerBlockHeight || null;
  row.chainLedgerBlockHash = transaction.ledgerBlockHash || null;
  row.chainLedgerMinedAt = transaction.minedAt || null;
  row.chainLedgerAnchored = Boolean((mined?.created || row.chainLedgerAnchored) && row.chainLedgerBlockHeight);
}

function syncRewardReviewMetadata(reward, row) {
  if (!reward) return;
  reward.metadata = {
    ...(reward.metadata || {}),
    reviewDecision: {
      id: row.id,
      decision: row.decision,
      reviewer: row.reviewer,
      reason: row.reason,
      reviewedAt: row.reviewedAt,
      chainTransactionId: row.chainTransactionId,
      txHash: row.txHash,
      chainMockBlockHeight: row.chainMockBlockHeight,
      chainLedgerBlockHeight: row.chainLedgerBlockHeight,
      chainLedgerBlockHash: row.chainLedgerBlockHash,
      chainLedgerAnchored: row.chainLedgerAnchored
    }
  };
}

async function recordDecision({ rewardId, decision, reviewer, reason } = {}) {
  const state = getState();
  const reward = (state.rewardEntries || []).find((entry) => entry.id === rewardId);
  if (!reward) throw new Error('Reward entry not found.');

  const normalizedDecision = String(decision || 'WATCH').trim().toUpperCase();
  if (!ALLOWED_DECISIONS.has(normalizedDecision)) throw new Error('Unsupported reward review decision.');

  const existingRows = Array.isArray(state.rewardReviewDecisions) ? state.rewardReviewDecisions : [];
  const filtered = existingRows.filter((row) => row.rewardId !== reward.id);
  const row = new RewardReviewDecision({
    rewardId: reward.id,
    decision: normalizedDecision,
    reviewer,
    reason,
    flags: reward.flags || [],
    previousRewardAmount: reward.rewardAmount
  });
  const transaction = await chainTransactionService.submitTransaction(buildReviewTransactionPayload(row, reward));
  attachTransaction(row, transaction);

  const mined = blockService.minePendingProofs({ limit: 1, reason: 'reward-review-decision' });
  const anchoredTransaction = chainTransactionService.getTransaction(transaction.id) || transaction;
  attachLedgerAnchor(row, anchoredTransaction, mined);
  syncRewardReviewMetadata(reward, row);

  state.rewardReviewDecisions = [row, ...filtered];
  persistentStore.writeState(state);
  return row;
}

async function repairAnchors({ limit = 25, reviewer = 'anchor-repair' } = {}) {
  const state = getState();
  const rows = Array.isArray(state.rewardReviewDecisions) ? state.rewardReviewDecisions : [];
  const candidates = rows.filter((row) => !row.chainTransactionId || !row.txHash || !row.chainLedgerBlockHeight).slice(0, Math.max(1, Number(limit || 25)));
  const results = [];

  for (const row of candidates) {
    const reward = (state.rewardEntries || []).find((entry) => entry.id === row.rewardId);
    let transaction = chainTransactionService.getTransaction(row.chainTransactionId || row.txHash);
    const beforeAnchored = Boolean(row.chainLedgerBlockHeight);

    if (!transaction) {
      transaction = await chainTransactionService.submitTransaction({
        ...buildReviewTransactionPayload(row, reward),
        actorId: reviewer || row.reviewer || 'anchor-repair',
        metadata: {
          ...buildReviewTransactionPayload(row, reward).metadata,
          repair: true,
          repairedAt: new Date().toISOString()
        }
      });
      attachTransaction(row, transaction);
    }

    const mined = transaction.ledgerBlockHeight ? null : blockService.minePendingProofs({ limit: 1, reason: 'reward-review-anchor-repair' });
    const anchoredTransaction = chainTransactionService.getTransaction(transaction.id || transaction.txHash) || transaction;
    attachLedgerAnchor(row, anchoredTransaction, mined);
    syncRewardReviewMetadata(reward, row);

    results.push({
      decisionId: row.id,
      rewardId: row.rewardId,
      txHash: row.txHash,
      repairedTx: Boolean(transaction),
      beforeAnchored,
      anchored: Boolean(row.chainLedgerBlockHeight),
      ledgerBlockHeight: row.chainLedgerBlockHeight || null
    });
  }

  if (candidates.length) persistentStore.writeState(state);

  return {
    ok: true,
    scanned: candidates.length,
    repaired: results.filter((row) => row.anchored || row.txHash).length,
    anchored: results.filter((row) => row.anchored).length,
    results
  };
}

function getStats() {
  const rows = listDecisions();
  const anchoredRows = rows.filter((row) => Boolean(row.chainLedgerBlockHeight || row.chainLedgerAnchored));
  const txRows = rows.filter((row) => Boolean(row.chainTransactionId || row.txHash));
  const pendingAnchorRows = rows.filter((row) => (row.chainTransactionId || row.txHash) && !row.chainLedgerBlockHeight);
  const missingTxRows = rows.filter((row) => !row.chainTransactionId && !row.txHash);
  return {
    decisionCount: rows.length,
    approveCount: rows.filter((row) => row.decision === 'APPROVE').length,
    watchCount: rows.filter((row) => row.decision === 'WATCH').length,
    rejectCount: rows.filter((row) => row.decision === 'REJECT').length,
    chainTxCount: txRows.length,
    anchoredCount: anchoredRows.length,
    pendingAnchorCount: pendingAnchorRows.length,
    missingTxCount: missingTxRows.length,
    latestAnchoredDecisions: anchoredRows.slice(0, 5),
    latestPendingAnchors: pendingAnchorRows.slice(0, 5),
    latestMissingTx: missingTxRows.slice(0, 5),
    latestDecisions: rows.slice(0, 10)
  };
}

module.exports = {
  getDecisionForReward,
  getStats,
  listDecisions,
  repairAnchors,
  recordDecision
};
