/**
 * Six-level nuanced vote evaluation.
 *
 * Exact TypeScript port of backend/app/engine/nuanced_vote.py
 * (Python is the reference implementation).
 *
 * Levels:
 *   0 - CONTRE
 *   1 - PAS DU TOUT
 *   2 - PAS D'ACCORD
 *   3 - NEUTRE
 *   4 - D'ACCORD
 *   5 - TOUT A FAIT
 *
 * Adoption rule:
 *   The sum of votes at levels 3 + 4 + 5 must be >= thresholdPct% of total votes.
 *   A minimum number of participants is also required.
 */

export const LEVEL_LABELS: Record<number, string> = {
  0: 'CONTRE',
  1: 'PAS DU TOUT',
  2: "PAS D'ACCORD",
  3: 'NEUTRE',
  4: "D'ACCORD",
  5: 'TOUT A FAIT',
}

export const NUM_LEVELS = 6

/** Result shape mirrors the Python dict returned by evaluate_nuanced(). */
export interface NuancedResult {
  total: number
  per_level_counts: Record<number, number>
  positive_count: number
  positive_pct: number
  threshold_met: boolean
  min_participants_met: boolean
  adopted: boolean
}

/**
 * Round to 2 decimals with ties-to-even, mirroring Python's round(x, 2).
 */
function round2(value: number): number {
  const scaled = value * 100
  const floor = Math.floor(scaled)
  const diff = scaled - floor
  let rounded: number
  if (diff > 0.5) {
    rounded = floor + 1
  } else if (diff < 0.5) {
    rounded = floor
  } else {
    rounded = floor % 2 === 0 ? floor : floor + 1
  }
  return rounded / 100
}

/**
 * Evaluate a nuanced vote from a list of individual vote levels.
 *
 * @param votes - List of vote levels (each 0-5), one entry per voter
 * @param thresholdPct - Minimum percentage of positive votes (levels 3-5) for adoption
 * @param minParticipants - Minimum number of participants required for validity
 * @returns Aggregated result (counts, percentage, adoption flags)
 * @throws Error if any vote value is outside the 0-5 integer range
 */
export function nuancedResult(
  votes: number[],
  thresholdPct: number = 80,
  minParticipants: number = 59,
): NuancedResult {
  // Validate vote levels (integer check added: JS has no KeyError safety net)
  for (const v of votes) {
    if (!Number.isInteger(v) || v < 0 || v > 5) {
      throw new Error(`Niveau de vote invalide : ${v}. Les niveaux valides sont 0-5.`)
    }
  }

  const total = votes.length

  const perLevelCounts: Record<number, number> = {}
  for (let level = 0; level < NUM_LEVELS; level++) {
    perLevelCounts[level] = 0
  }
  for (const v of votes) {
    perLevelCounts[v] = (perLevelCounts[v] ?? 0) + 1
  }

  // Positive = levels 3 (NEUTRE), 4 (D'ACCORD), 5 (TOUT A FAIT)
  const positiveCount = (perLevelCounts[3] ?? 0) + (perLevelCounts[4] ?? 0) + (perLevelCounts[5] ?? 0)

  const positivePct = total > 0 ? (positiveCount / total) * 100.0 : 0.0

  const thresholdMet = positivePct >= thresholdPct
  const minParticipantsMet = total >= minParticipants
  const adopted = thresholdMet && minParticipantsMet

  return {
    total,
    per_level_counts: perLevelCounts,
    positive_count: positiveCount,
    positive_pct: round2(positivePct),
    threshold_met: thresholdMet,
    min_participants_met: minParticipantsMet,
    adopted,
  }
}
