from typing import Any, ClassVar, Self

from django.db import models
from django.db.models import QuerySet
from treebeard.models import Node
from treebeard.numconv import NumConv

class MP_NodeQuerySet(models.QuerySet["MP_Node"]):
    def delete(self, *args: Any, **kwargs: Any) -> tuple[int, dict[str, int]]: ...

class MP_NodeManager(models.Manager["MP_Node"]):
    def get_queryset(self) -> MP_NodeQuerySet: ...

class MP_ComplexAddMoveHandler:
    node_cls: type[MP_Node]
    def increment_numchild(self, path: str) -> None: ...
    def decrement_numchild(self, path: str) -> None: ...
    def reorder_nodes_before_add_or_move(
        self,
        pos: str,
        newpos: int | None,
        newdepth: int,
        target: MP_Node,
        siblings: QuerySet[MP_Node] | list[MP_Node],
        oldpath: str | None = ...,
        movebranch: bool = ...,
    ) -> tuple[str | None, str]: ...
    def set_newpath_in_branches(self, oldpath: str, newpath: str) -> None: ...

class MP_AddRootHandler:
    cls: type[MP_Node]
    kwargs: dict[str, Any]
    def __init__(self, cls: type[MP_Node], **kwargs: Any) -> None: ...
    def process(self) -> MP_Node: ...

class MP_AddChildHandler:
    node: MP_Node
    node_cls: type[MP_Node]
    kwargs: dict[str, Any]
    def __init__(self, node: MP_Node, creation_kwargs: dict[str, Any]) -> None: ...
    def process(self) -> MP_Node: ...

class MP_AddSiblingHandler(MP_ComplexAddMoveHandler):
    node: MP_Node
    node_cls: type[MP_Node]
    pos: str
    kwargs: dict[str, Any]
    def __init__(self, node: MP_Node, pos: str | None, creation_kwargs: dict[str, Any]) -> None: ...
    def process(self) -> MP_Node: ...

class MP_MoveHandler(MP_ComplexAddMoveHandler):
    node: MP_Node
    node_cls: type[MP_Node]
    target: MP_Node
    pos: str | None
    def __init__(self, node: MP_Node, target: MP_Node, pos: str | None = ...) -> None: ...
    def process(self) -> None: ...
    def update_parent_counts_after_move(self, oldpath: str, newpath: str) -> None: ...
    def update_move_to_child_vars(self) -> tuple[int, list[MP_Node] | QuerySet[MP_Node], int | None]: ...

class MP_Node(Node):
    steplen: int
    alphabet: str
    node_order_by: list[str]
    path: models.CharField[str, str]
    depth: models.PositiveIntegerField[int, int]
    numchild: models.PositiveIntegerField[int, int]

    TREEBEARD_IDENTIFYING_FIELD: str
    MOVENODE_FORM_EXCLUDED_FIELDS: tuple[str, ...]

    objects: ClassVar[MP_NodeManager]  # type: ignore[assignment]

    numconv_obj_: NumConv | None

    @classmethod
    def numconv_obj(cls) -> NumConv: ...
    @classmethod
    def add_root(cls, **kwargs: Any) -> Self: ...
    @classmethod
    def dump_bulk(cls, parent: Self | None = ..., keep_ids: bool = ...) -> list[dict[str, Any]]: ...
    @classmethod
    def find_problems(cls) -> tuple[list[int], list[int], list[int], list[int], list[int]]: ...
    @classmethod
    def fix_tree(cls, fix_paths: bool = ..., parent: Self | None = ...) -> None: ...
    @classmethod
    def get_tree(cls, parent: Self | None = ...) -> QuerySet[Self]: ...
    @classmethod
    def get_root_nodes(cls) -> QuerySet[Self]: ...
    @classmethod
    def get_descendants_group_count(cls, parent: Self | None = ...) -> QuerySet[Self]: ...
    def get_depth(self) -> int: ...
    def get_siblings(self) -> QuerySet[Self]: ...
    def get_children(self) -> QuerySet[Self]: ...
    def get_next_sibling(self) -> Self | None: ...
    def get_descendants(self, include_self: bool = ...) -> QuerySet[Self]: ...
    def get_prev_sibling(self) -> Self | None: ...
    def get_children_count(self) -> int: ...
    def is_sibling_of(self, node: Self) -> bool: ...
    def is_child_of(self, node: Self) -> bool: ...
    def is_descendant_of(self, node: Self) -> bool: ...
    def add_child(self, **kwargs: Any) -> Self: ...
    def add_sibling(self, pos: str | None = ..., **kwargs: Any) -> Self: ...
    def get_root(self) -> Self: ...
    def is_root(self) -> bool: ...
    def is_leaf(self) -> bool: ...
    def get_ancestors(self) -> QuerySet[Self]: ...
    def get_parent(self, update: bool = ...) -> Self | None: ...
    def move(self, target: Self, pos: str | None = ...) -> None: ...

    class Meta:
        abstract: bool
