import enum
from typing import overload

# ========== project enums ==========

class Comparator(enum.Enum):
    COST: Comparator
    VOTES: Comparator
    LEXICOGRAPHIC: Comparator

class Ordering(enum.Enum):
    ASCENDING: Ordering
    DESCENDING: Ordering

# ========== project classes ==========

class Election:
    def __init__(self, budget: int, num_of_voters: int, projects: list[ProjectEmbedding]) -> None: ...
    @property
    def budget(self) -> int: ...
    @property
    def num_of_voters(self) -> int: ...
    @property
    def projects(self) -> list[ProjectEmbedding]: ...

class ProjectEmbedding:
    def __init__(self, cost: int, name: str, approvers: list[int] = ...) -> None: ...
    @property
    def cost(self) -> int: ...
    @property
    def name(self) -> str: ...
    @property
    def approvers(self) -> list[int]: ...
    @property
    def num_of_approvers(self) -> int: ...

class ProjectComparator:
    ByCostAsc: ProjectComparator
    ByCostDesc: ProjectComparator
    ByNameAsc: ProjectComparator
    ByNameDesc: ProjectComparator
    ByVotesDesc: ProjectComparator
    ByCostAscThenVotesDesc: ProjectComparator
    ByCostDescThenVotesDesc: ProjectComparator

    @overload
    def __init__(self, criteria: list[tuple[Comparator, Ordering]]) -> None: ...
    @overload
    def __init__(self, comparator: Comparator, ordering: Ordering) -> None: ...
    def __init__(self, *args, **kwargs) -> None: ...
    def __call__(self, lhs: ProjectEmbedding, rhs: ProjectEmbedding) -> bool: ...

# ========== rules ==========

def greedy(election: Election, tie_breaking: ProjectComparator) -> list[ProjectEmbedding]: ...
def greedy_over_cost(election: Election, tie_breaking: ProjectComparator) -> list[ProjectEmbedding]: ...
def mes_apr(election: Election, tie_breaking: ProjectComparator) -> list[ProjectEmbedding]: ...
def mes_cost(election: Election, tie_breaking: ProjectComparator) -> list[ProjectEmbedding]: ...
def phragmen(election: Election, tie_breaking: ProjectComparator) -> list[ProjectEmbedding]: ...

# ========== optimist-add ==========

def optimist_add_for_greedy(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...
def optimist_add_for_greedy_over_cost(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...
def optimist_add_for_mes_apr(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...
def optimist_add_for_mes_cost(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...
def optimist_add_for_phragmen(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...

# ========== pessimist-add ==========

def pessimist_add_for_greedy(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...
def pessimist_add_for_greedy_over_cost(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...
def pessimist_add_for_mes_apr(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...
def pessimist_add_for_mes_cost(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...
def pessimist_add_for_phragmen(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...

# ========== singleton-add ==========

def singleton_add_for_greedy(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...
def singleton_add_for_greedy_over_cost(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...
def singleton_add_for_mes_apr(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...
def singleton_add_for_mes_cost(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...
def singleton_add_for_phragmen(election: Election, p: int, tie_breaking: ProjectComparator) -> int | None: ...

# ========== cost-reduction ==========

def cost_reduction_for_greedy(election: Election, p: int, tie_breaking: ProjectComparator) -> int: ...
def cost_reduction_for_greedy_over_cost(election: Election, p: int, tie_breaking: ProjectComparator) -> int: ...
def cost_reduction_for_mes_apr(election: Election, p: int, tie_breaking: ProjectComparator) -> int: ...
def cost_reduction_for_mes_cost(election: Election, p: int, tie_breaking: ProjectComparator) -> int: ...
def cost_reduction_for_phragmen(election: Election, p: int, tie_breaking: ProjectComparator) -> int: ...
