"""
Parent class for all type annotation wrappers.
"""
from abc import ABC, abstractmethod
from collections.abc import Iterator
from typing import TypeVar

from mypy_boto3_builder.import_helpers.import_record import ImportRecord
from mypy_boto3_builder.import_helpers.import_string import ImportString

_R = TypeVar("_R", bound="FakeAnnotation")


class FakeAnnotation(ABC):
    """
    Parent class for all type annotation wrappers.
    """

    _sys_import_record = ImportRecord(ImportString("sys"))

    def __hash__(self) -> int:
        return hash(self.render())

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, FakeAnnotation):
            return False

        return self.get_sort_key() == other.get_sort_key()

    def __lt__(self, other: "FakeAnnotation") -> bool:
        return self.get_sort_key() < other.get_sort_key()

    def __gt__(self, other: "FakeAnnotation") -> bool:
        return self.get_sort_key() > other.get_sort_key()

    def get_sort_key(self) -> str:
        """
        Get string to sort annotations.
        """
        return str(self)

    def __str__(self) -> str:
        return self.render()

    @abstractmethod
    def render(self, parent_name: str = "") -> str:
        """
        Render type annotation to a valid Python code for local usage.
        """

    def _get_import_records(self) -> set[ImportRecord]:
        """
        Get import record required for using type annotation.
        """
        return set()

    def get_import_records(self) -> set[ImportRecord]:
        """
        Get all import records required for using type annotation.
        """
        result: set[ImportRecord] = set()
        import_records = self._get_import_records()
        for import_record in import_records:
            if not import_record.is_empty() and not import_record.is_builtins():
                result.add(import_record)
            if import_record.needs_sys_fallback():
                result.add(self._sys_import_record)

        return result

    def iterate_types(self) -> Iterator["FakeAnnotation"]:
        """
        Iterate over all used type annotations recursively including self.
        """
        yield self

    def is_dict(self) -> bool:
        """
        Whether type annotation is `Dict` or `TypedDict`.
        """
        return False

    def is_typed_dict(self) -> bool:
        """
        Whether type annotation is `TypedDict`.
        """
        return False

    def is_list(self) -> bool:
        """
        Whether type annotation is `List`.
        """
        return False

    def is_literal(self) -> bool:
        """
        Whether type annotation is `Literal`.
        """
        return False

    @abstractmethod
    def copy(self: _R) -> _R:
        """
        Create a copy of type annotation wrapper.
        """

    def get_local_types(self) -> list["FakeAnnotation"]:
        """
        Get internal types generated by builder.
        """
        return []
