from __future__ import annotations
import datetime
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Union
from datafinder.typed_attributes import *
from datafinder import FinderResult
from datafinder.attribute import Attribute
from model.relational import NoOperation, CountAllOperation, Operation

{% for rpm in rcm.property_mappings %}
{% if not is_primitive(rpm.property) and rpm.property.type.name != rcm.clazz.name %}
if TYPE_CHECKING:
    from {{class_module_map_base[rpm.property.type.name]}} import {{rpm.property.type.name}}RelatedFinderBase
{% endif %}
{% endfor %}
{% for source_rcm, rpm, assoc, reverse_name in reverse_assocs %}
if TYPE_CHECKING:
    from {{class_module_map_base[source_rcm.clazz.name]}} import {{source_rcm.clazz.name}}RelatedFinderBase
{% endfor %}


class {{rcm.clazz.name}}RelatedFinderBase(ABC):
{% for rpm in rcm.property_mappings %}
{% if is_primitive(rpm.property) %}
    @abstractmethod
    def {{to_python_name(rpm.property)}}(self) -> {{rpm.property.type.name}}Attribute: ...

{% elif rpm.property.type.name != rcm.clazz.name %}
    @abstractmethod
    def {{to_python_name(rpm.property)}}(self, **kwargs) -> {{rpm.property.type.name}}RelatedFinderBase: ...

{% endif %}
{% endfor %}
{% for source_rcm, rpm, assoc, reverse_name in reverse_assocs %}
    @abstractmethod
    def {{reverse_name}}(self, **kwargs) -> {{source_rcm.clazz.name}}RelatedFinderBase: ...

{% endfor %}

class {{rcm.clazz.name}}FinderBase(ABC):
{% for rpm in rcm.property_mappings %}
{% if is_primitive(rpm.property) %}
    @abstractmethod
    def {{to_python_name(rpm.property)}}(self) -> {{rpm.property.type.name}}Attribute: ...

{% elif rpm.property.type.name != rcm.clazz.name %}
    @abstractmethod
    def {{to_python_name(rpm.property)}}(self, **kwargs) -> {{rpm.property.type.name}}RelatedFinderBase: ...

{% endif %}
{% endfor %}
{% for source_rcm, rpm, assoc, reverse_name in reverse_assocs %}
    @abstractmethod
    def {{reverse_name}}(self, **kwargs) -> {{source_rcm.clazz.name}}RelatedFinderBase: ...

{% endfor %}
    @abstractmethod
    def count(self) -> CountAllOperation: ...

    @abstractmethod
    def find_all(self,
                 business_date: Union[datetime.date, str],
                 processing_valid_at: Union[datetime.datetime, str],
                 display_columns: list[Attribute],
                 filter_op: Operation = NoOperation()) -> FinderResult: ...
{% if rcm.milestone_mapping and (has_bitemporal(rcm.milestone_mapping) or has_business_date_and_processing(rcm.milestone_mapping) or has_uni_business_temporal(rcm.milestone_mapping)) %}

    @abstractmethod
    def find_for_date_range(self,
                            business_date_from: Union[datetime.date, str],
                            business_date_to: Union[datetime.date, str],
                            processing_valid_at: Union[datetime.datetime, str],
                            display_columns: list[Attribute],
                            filter_op: Operation = NoOperation()) -> FinderResult: ...
{% endif %}
