from typing import Any, ClassVar, final

from tree_sitter import Language

@final
class Node:
    @property
    def start_byte(self) -> int: ...
    @property
    def start_point(self) -> tuple[int, int]: ...
    @property
    def end_byte(self) -> int: ...
    @property
    def end_point(self) -> tuple[int, int]: ...
    @property
    def has_changes(self) -> bool: ...
    @property
    def has_error(self) -> bool: ...
    @property
    def id(self) -> int: ...
    @property
    def is_missing(self) -> bool: ...
    @property
    def is_named(self) -> bool: ...
    @property
    def child_count(self) -> int: ...
    @property
    def named_child_count(self) -> bool: ...
    @property
    def children(self) -> list[Node]: ...
    @property
    def named_children(self) -> list[Node]: ...
    @property
    def next_named_sibling(self) -> Node | None: ...
    @property
    def next_sibling(self) -> Node | None: ...
    @property
    def parent(self) -> Node | None: ...
    @property
    def prev_named_sibling(self) -> Node | None: ...
    @property
    def prev_sibling(self) -> Node | None: ...
    @property
    def text(self) -> bytes | Any: ...  # can be None, but annoying to check
    @property
    def type(self) -> str: ...
    def children_by_field_name(self, name: str) -> list[Node]: ...
    def children_by_field_id(self, id: int, /) -> list[Node]: ...
    def field_name_for_child(self, child_index: int, /) -> str: ...
    def child_by_field_id(self, id: int, /) -> Node | None: ...
    def child_by_field_name(self, name: str, /) -> Node | None: ...
    __hash__: ClassVar[None]  # type: ignore[assignment]
    def sexp(self) -> str: ...
    def walk(self) -> TreeCursor: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    # There are __ge__, __gt__, __le__, __lt__ methods but they always return False
    #
    #    >>> n
    #    <Node kind=call, start_point=(0, 0), end_point=(0, 14)>
    #    >>> n >= "", n <= "", n >= 0, n <= 0, n >= (0,0), n <= (0,0)
    #    (False, False, False, False, False, False)

@final
class Parser:
    # At runtime, Parser(1, 2, 3) ignores the arguments, but that's most likely buggy code
    def __init__(self) -> None: ...
    def parse(self, source: bytes, old_tree: Tree | None = None, keep_text: bool = True) -> Tree: ...
    def set_language(self, language: Language, /) -> None: ...

@final
class Query:
    # start_point and end_point arguments don't seem to do anything
    # TODO: sync with
    # https://github.com/tree-sitter/py-tree-sitter/blob/d3016edac2c33ce647653d896fbfb435ac2a6245/tree_sitter/binding.c#L1304
    def captures(self, node: Node) -> list[tuple[Node, str]]: ...

@final
class Range:
    @property
    def start_byte(self) -> int: ...
    @property
    def end_byte(self) -> int: ...
    @property
    def start_point(self) -> tuple[int, int]: ...
    @property
    def end_point(self) -> tuple[int, int]: ...

@final
class Tree:
    @property
    def root_node(self) -> Node: ...
    @property
    def text(self) -> bytes | Any: ...  # technically ReadableBuffer | Any
    def edit(
        self,
        start_byte: int,
        old_end_byte: int,
        new_end_byte: int,
        start_point: tuple[int, int],
        old_end_point: tuple[int, int],
        new_end_point: tuple[int, int],
    ) -> None: ...
    def get_changed_ranges(self, new_tree: Tree) -> list[Range]: ...
    def walk(self) -> TreeCursor: ...

@final
class TreeCursor:
    @property
    def node(self) -> Node: ...
    def copy(self) -> TreeCursor: ...
    def current_field_name(self) -> str | None: ...
    def goto_first_child(self) -> bool: ...
    def goto_next_sibling(self) -> bool: ...
    def goto_parent(self) -> bool: ...
