import heapq
import math
from itertools import chain, combinations, zip_longest
from operator import itemgetter

from numpy.typing import ArrayLike

from ..classes.digraph import DiGraph
from ..classes.graph import Graph
from ..classes.multidigraph import MultiDiGraph
from ..classes.multigraph import MultiGraph
from ..utils import py_random_state, random_weighted_sample

__all__ = [
    "configuration_model",
    "directed_configuration_model",
    "expected_degree_graph",
    "havel_hakimi_graph",
    "directed_havel_hakimi_graph",
    "degree_sequence_tree",
    "random_degree_sequence_graph",
]

chaini = ...

@py_random_state(2)
def configuration_model(deg_sequence, create_using=None, seed=None) -> MultiGraph: ...
@py_random_state(3)
def directed_configuration_model(in_degree_sequence, out_degree_sequence, create_using=None, seed=None) -> MultiDiGraph: ...
@py_random_state(1)
def expected_degree_graph(w: ArrayLike, seed=None, selfloops=True) -> Graph: ...
def havel_hakimi_graph(deg_sequence, create_using=None): ...
def directed_havel_hakimi_graph(in_deg_sequence, out_deg_sequence, create_using=None) -> DiGraph: ...
def degree_sequence_tree(deg_sequence, create_using=None): ...
@py_random_state(1)
def random_degree_sequence_graph(sequence, seed=None, tries: int = 10) -> Graph: ...

class DegreeSequenceRandomGraph:
    # class to generate random graphs with a given degree sequence
    # use random_degree_sequence_graph()
    def __init__(self, degree, rng): ...
    def generate(self): ...
    def update_remaining(self, u, v, aux_graph=None): ...
    def p(self, u, v): ...
    def q(self, u, v): ...
    def suitable_edge(self): ...
    def phase1(self): ...
    def phase2(self): ...
    def phase3(self): ...
