#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#
from typing import (
    overload,
    Generic,
    Union,
    Iterable,
    Tuple,
    List,
    Mapping,
    Optional,
    Sequence,
    TypeVar,
    Type,
    Dict,
    Any,
)

from ._project import Project

TNode = TypeVar("TNode", bound="Node")
TValidNodeValue = TypeVar("TValidNodeValue", int, str, bool, Mapping, Sequence)

class ProvenanceInformation: ...

class Node:
    def clone(self) -> "Node": ...
    def get_provenance(self) -> ProvenanceInformation: ...
    def strip_node_info(self) -> Dict[str, Any]: ...
    # FIXME: We should be able to annotate more specifically what is allowed
    #        in the dictionary here, but this requires recursive type annotations
    #        which appears to not yet be properly supported.
    #
    #        See: https://github.com/python/mypy/issues/731
    #
    @classmethod
    def from_dict(cls, value: Dict[str, Any]) -> "MappingNode": ...

class ScalarNode(Node):
    def as_str(self) -> str: ...
    def clone(self) -> "ScalarNode": ...

class SequenceNode(Node, Generic[TNode]):
    def __iter__(self) -> "SequenceNode": ...
    def __next__(self) -> Any: ...
    def as_str_list(self) -> List[str]: ...
    def clone(self) -> "SequenceNode[TNode]": ...

class MappingNode(Node, Generic[TNode]):
    def __init__(self, file_index: int, line: int, column: int, value: Mapping[str, TValidNodeValue]) -> None: ...
    def __contains__(self, what: Any) -> bool: ...
    def clone(self) -> MappingNode[TNode]: ...
    def keys(self) -> Iterable[str]: ...
    def items(self) -> Iterable[Tuple[str, Any]]: ...
    def safe_del(self, key: str) -> None: ...
    def validate_keys(self, valid_keys: List[str]): ...
    def values(self) -> List[Node]: ...
    @overload
    def get_scalar(self, key: str) -> ScalarNode: ...
    @overload
    def get_scalar(self, key: str, default: Union[str, int, bool, None]) -> ScalarNode: ...
    @overload
    def get_bool(self, key: str) -> bool: ...
    @overload
    def get_bool(self, key: str, default: bool) -> bool: ...
    @overload
    def get_str_list(self, key: str) -> List[str]: ...
    @overload
    def get_str_list(self, key: str, default: List[str]) -> List[str]: ...
    @overload
    def get_str_list(self, key: str, default: Optional[List[str]]) -> Optional[List[str]]: ...
    @overload
    def get_str(self, key: str) -> str: ...
    @overload
    def get_str(self, key: str, default: str) -> str: ...
    @overload
    def get_str(self, key: str, default: Optional[str]) -> Optional[str]: ...
    @overload
    def get_int(self, key: str) -> int: ...
    @overload
    def get_int(self, key: str, default: int) -> int: ...
    @overload
    def get_int(self, key: str, default: Optional[int]) -> Optional[int]: ...
    @overload
    def get_enum(self, key: str, constraint: object) -> str: ...
    @overload
    def get_enum(self, key: str, constraint: object, default: Optional[object]) -> Optional[str]: ...
    @overload
    def get_mapping(self, key: str) -> "MappingNode": ...
    @overload
    def get_mapping(self, key: str, default: Union["MappingNode", Dict[str, Any]]) -> "MappingNode": ...
    @overload
    def get_mapping(
        self, key: str, default: Union["MappingNode", Dict[str, Any], None]
    ) -> Optional["MappingNode"]: ...
    @overload
    def get_sequence(self, key: str, *, allowed_types: Optional[List[Type[Node]]]) -> SequenceNode: ...
    @overload
    def get_sequence(
        self, key: str, default: List[Any], *, allowed_types: Optional[List[Type[Node]]]
    ) -> SequenceNode: ...
    @overload
    def get_sequence(
        self, key: str, default: Optional[List[Any]], *, allowed_types: Optional[List[Type[Node]]]
    ) -> Optional[SequenceNode]: ...
    @overload
    def get_node(self, key: str) -> Node: ...
    @overload
    def get_node(self, key: str, allowed_types: Optional[List[Type[Node]]]) -> Node: ...
    @overload
    def get_node(self, key: str, allowed_types: Optional[List[Type[Node]]], allow_none: bool) -> Optional[Node]: ...
    #
    # Private
    #
    def _composite(self, target: "MappingNode") -> None: ...

def _assert_symbol_name(
    symbol_name: str, purpose: str, *, ref_node: Optional[Node], allow_dashes: bool = True
) -> None: ...
def _new_synthetic_file(filename: str, project: Optional[Project]) -> MappingNode[TNode]: ...
