from typing import Any, ClassVar, Self

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

def merge_deleted_counters(
    c1: tuple[int, dict[str, int]], c2: tuple[int, dict[str, int]]
) -> tuple[int, dict[str, int]]: ...

class NS_NodeQuerySet(models.QuerySet["NS_Node"]):
    def delete(
        self,
        *args: Any,
        removed_ranges: list[tuple[int, int, int]] | None = ...,
        deleted_counter: tuple[int, dict[str, int]] | None = ...,
        **kwargs: Any,
    ) -> tuple[int, dict[str, int]]: ...

class NS_NodeManager(models.Manager["NS_Node"]):
    def get_queryset(self) -> NS_NodeQuerySet: ...

class NS_Node(Node):
    node_order_by: list[str]
    lft: models.PositiveIntegerField[int, int]
    rgt: models.PositiveIntegerField[int, int]
    tree_id: models.PositiveIntegerField[int, int]
    depth: models.PositiveIntegerField[int, int]

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

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

    @classmethod
    def add_root(cls, **kwargs: Any) -> Self: ...
    def add_child(self, **kwargs: Any) -> Self: ...
    def add_sibling(self, pos: str | None = ..., **kwargs: Any) -> Self: ...
    def move(self, target: Self, pos: str | None = ...) -> None: ...
    def get_children(self) -> QuerySet[Self]: ...
    def get_depth(self) -> int: ...
    def is_leaf(self) -> bool: ...
    def get_root(self) -> Self: ...
    def is_root(self) -> bool: ...
    def get_siblings(self) -> QuerySet[Self]: ...
    @classmethod
    def dump_bulk(cls, parent: Self | None = ..., keep_ids: bool = ...) -> list[dict[str, Any]]: ...
    @classmethod
    def get_tree(cls, parent: Self | None = ...) -> QuerySet[Self]: ...
    def get_descendants(self, include_self: bool = ...) -> QuerySet[Self]: ...
    def get_descendant_count(self) -> int: ...  # Runtime returns float but base class declares int; keeping int for LSP
    def get_ancestors(self) -> QuerySet[Self]: ...
    def is_descendant_of(self, node: Self) -> bool: ...
    def get_parent(self, update: bool = ...) -> Self | None: ...
    @classmethod
    def get_root_nodes(cls) -> QuerySet[Self]: ...

    class Meta:
        abstract: bool
