"""WoT members threshold formula for binary votes.

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)
"""

from __future__ import annotations

import math


def wot_threshold(
    wot_size: int,
    total_votes: int,
    majority_pct: int = 50,
    base_exponent: float = 0.1,
    gradient_exponent: float = 0.2,
    constant_base: float = 0.0,
) -> int:
    """Compute the minimum number of *for* votes required for adoption.

    Parameters
    ----------
    wot_size:
        Size of the eligible voter corpus (WoT members).
    total_votes:
        Number of votes cast (for + against).
    majority_pct:
        Majority percentage (0-100). 50 = simple majority at full participation.
    base_exponent:
        B in the formula.  ``B^W`` contributes a vanishingly small offset
        when W is large (0 < B < 1).
    gradient_exponent:
        G controls how fast the required super-majority decays toward M as
        participation increases.
    constant_base:
        C, a fixed additive floor on the threshold.

    Returns
    -------
    int
        The ceiling of the computed threshold.  A vote passes when
        ``votes_for >= wot_threshold(...)``.
    """
    if wot_size <= 0:
        raise ValueError("wot_size doit etre strictement positif")
    if total_votes < 0:
        raise ValueError("total_votes ne peut pas etre negatif")
    if not (0 <= majority_pct <= 100):
        raise ValueError("majority_pct doit etre entre 0 et 100")

    C = constant_base
    B = base_exponent
    W = wot_size
    T = total_votes
    M = majority_pct / 100.0
    G = gradient_exponent

    # Guard: if no votes, threshold is at least ceil(C + B^W)
    if T == 0:
        return math.ceil(C + B ** W)

    # Core formula
    participation_ratio = T / W
    inertia_factor = 1.0 - participation_ratio ** G
    required_ratio = M + (1.0 - M) * inertia_factor
    result = C + B ** W + required_ratio * max(0.0, T - C)

    return math.ceil(result)
