/**
 * TypeScript mirror of the Python WoT threshold formula.
 *
 * Core formula:
 *   Result = C + B^W + (M + (1-M) * (1 - (T/W)^G)) * max(0, T - C)
 *
 * Where:
 *   C = constant_base
 *   B = base_exponent
 *   W = wot_size (corpus of eligible voters)
 *   T = total_votes (for + against)
 *   M = majority_ratio (majority_pct / 100)
 *   G = gradient_exponent
 *
 * Inertia behaviour:
 *   - Low participation (T << W) -> near-unanimity required
 *   - High participation (T -> W) -> simple majority M suffices
 *
 * Reference test case:
 *   wot_size=7224, votes_for=97, votes_against=23 (total=120)
 *   params M50 B.1 G.2 => threshold=94, adopted (97 >= 94)
 */
export function wotThreshold(
  wotSize: number,
  totalVotes: number,
  majorityPct: number = 50,
  baseExponent: number = 0.1,
  gradientExponent: number = 0.2,
  constantBase: number = 0.0,
): number {
  if (wotSize <= 0) {
    throw new Error('wotSize doit etre strictement positif')
  }
  if (totalVotes < 0) {
    throw new Error('totalVotes ne peut pas etre negatif')
  }
  if (majorityPct < 0 || majorityPct > 100) {
    throw new Error('majorityPct doit etre entre 0 et 100')
  }

  const M = majorityPct / 100
  const T = totalVotes
  const W = wotSize
  const C = constantBase
  const B = baseExponent
  const G = gradientExponent

  // Guard: if no votes, threshold is at least ceil(C + B^W)
  if (T === 0) {
    return Math.ceil(C + Math.pow(B, W))
  }

  // Core formula
  const participationRatio = T / W
  const inertiaFactor = 1.0 - Math.pow(participationRatio, G)
  const requiredRatio = M + (1.0 - M) * inertiaFactor
  const result = C + Math.pow(B, W) + requiredRatio * Math.max(0, T - C)

  return Math.ceil(result)
}

/**
 * Compute the Smith criterion threshold.
 *
 * @param smithWotSize - Number of Smith members
 * @param smithExponent - Exponent S for the Smith criterion
 * @returns Minimum number of Smith votes required
 */
export function smithThreshold(smithWotSize: number, smithExponent: number): number {
  if (smithWotSize <= 0) return 0
  return Math.ceil(Math.pow(smithWotSize, smithExponent))
}

/**
 * Compute the TechComm criterion threshold.
 *
 * @param techcommSize - Number of TechComm members
 * @param techcommExponent - Exponent T for the TechComm criterion
 * @returns Minimum number of TechComm votes required
 */
export function techcommThreshold(techcommSize: number, techcommExponent: number): number {
  if (techcommSize <= 0) return 0
  return Math.ceil(Math.pow(techcommSize, techcommExponent))
}
