'use strict';

const {
  normalizeHarness,
  scoreHarness,
  selectAgentHarness,
} = require('../agent-runtime/harness');

function normalizeCandidate(candidate = {}) {
  const runnerId = candidate.runnerId || candidate.id;
  return {
    ...candidate,
    runnerId,
    providerType: candidate.providerType || candidate.provider || 'unknown',
  };
}

function numberOr(value, fallback) {
  if (value == null) return fallback;
  const n = Number(value);
  return Number.isFinite(n) ? n : fallback;
}

function scoreAgentRunner(stats = {}, candidate = {}) {
  const totalRuns = numberOr(stats.total_runs ?? stats.totalEvals, 0);
  const avgQuality = numberOr(stats.avg_quality, candidate.priorQuality ?? 0.55);
  const passRate = numberOr(stats.pass_rate ?? stats.review_pass_rate ?? stats.test_pass_rate, candidate.priorPassRate ?? 0.55);
  const avgLatencyMs = numberOr(stats.avg_latency_ms, candidate.priorLatencyMs ?? 180000);
  const avgRetries = numberOr(stats.avg_retries, 0);
  const confidenceBonus = Math.min(0.15, totalRuns / 100);
  const latencyPenalty = Math.min(0.20, avgLatencyMs / 1_200_000);
  const retryPenalty = Math.min(0.10, avgRetries * 0.03);

  return Math.max(0, Math.min(1,
    avgQuality * 0.55 +
    passRate * 0.30 +
    confidenceBonus -
    latencyPenalty -
    retryPenalty
  ));
}

function applyQuorumRiskScore(baseScore, stats = {}) {
  const passRate = numberOr(stats.pass_rate ?? stats.review_pass_rate, null);
  if (passRate == null) return baseScore;
  if (passRate < 0.4) return Math.max(0, baseScore - 0.20);
  if (passRate >= 0.85) return Math.min(1, baseScore + 0.05);
  return baseScore;
}

function selectBestAgentRunners(taskType, candidates = [], brain = null, opts = {}) {
  const count = Math.max(1, opts.count || 1);
  const days = opts.days || 30;
  const normalized = candidates.map(normalizeCandidate).filter(candidate => candidate.runnerId);

  const scored = normalized.map((candidate, index) => {
    let stats = null;
    try {
      stats = brain?.getAgentRunnerScorecard
        ? brain.getAgentRunnerScorecard(candidate.runnerId, taskType, days)
        : null;
    } catch {
      stats = null;
    }
    const score = applyQuorumRiskScore(scoreAgentRunner(stats || {}, candidate), stats || {});
    return { candidate, stats, score, index };
  });

  scored.sort((a, b) => {
    if (b.score !== a.score) return b.score - a.score;
    return a.index - b.index;
  });

  return scored.slice(0, count).map(entry => ({
    ...entry.candidate,
    score: entry.score,
    stats: entry.stats,
  }));
}

function selectBestAgentRunner(taskType, candidates = [], brain = null, opts = {}) {
  return selectBestAgentRunners(taskType, candidates, brain, { ...opts, count: 1 })[0] || null;
}

function selectBestAgentHarness(request = {}, candidates = [], brain = null, opts = {}) {
  const taskType = request.taskType || opts.taskType || 'coding:general';
  const normalized = candidates.map((candidate) => {
    const harness = normalizeHarness(candidate);
    let stats = null;
    try {
      stats = brain?.getAgentRunnerScorecard
        ? brain.getAgentRunnerScorecard(harness.runnerId, taskType, opts.days || 30)
        : null;
    } catch {
      stats = null;
    }
    const qualityScore = scoreAgentRunner(stats || {}, harness);
    return {
      ...harness,
      qualityScore,
      stats,
    };
  });
  const selection = selectAgentHarness(request, normalized, {
    ...opts,
    qualityScore: undefined,
    providerAvailability: opts.providerAvailability,
  });
  if (!selection.selected) return null;
  return {
    ...selection.selected,
    score: scoreHarness(selection.selected, request, {
      ...opts,
      providerAvailability: opts.providerAvailability,
      qualityScore: selection.selected.qualityScore,
    }),
    selection,
  };
}

module.exports = {
  applyQuorumRiskScore,
  normalizeCandidate,
  scoreAgentRunner,
  selectBestAgentRunner,
  selectBestAgentRunners,
  selectBestAgentHarness,
};
