from abc import ABC, abstractmethod
from typing import List, Optional

from analogai.foundation.modules.direct_statement.direct_statement import DirectStatement
from analogai.foundation.modules.notion.notion import Notion
from analogai.foundation.core.value_objects.modifier import Modifier
from analogai.foundation.core.value_objects.relation import Relation


class StatementRepository(ABC):
    @abstractmethod
    def create(self, statement: DirectStatement) -> DirectStatement:
        pass

    def update(self, statement: DirectStatement) -> DirectStatement:
        return statement

    @abstractmethod
    def delete(self, statement: DirectStatement) -> None:
        pass

    @abstractmethod
    def find_by_id(self, statement_id: str) -> Optional[DirectStatement]:
        pass

    @abstractmethod
    def find_by_subject(self, subject_notion: Notion) -> List[DirectStatement]:
        pass

    @abstractmethod
    def find_by_subject_and_relation(
        self,
        subject_notion: Notion,
        relation: Relation,
        modifier: Optional[Modifier] = None,
    ) -> List[DirectStatement]:
        pass

    @abstractmethod
    def find_by_object(self, complement_notion: Notion) -> List[DirectStatement]:
        pass

    @abstractmethod
    def find_by_object_and_relation(
        self,
        complement_notion: Notion,
        relation: Relation,
        modifier: Optional[Modifier] = None,
    ) -> List[DirectStatement]:
        pass

    def find_by_agent_id(
        self,
        agent_id: str,
        limit: int = 0,
        offset: int = 0,
    ) -> List[DirectStatement]:
        return []

    def find(
        self,
        subject_notion: Notion,
        complement_notion: Notion,
        relation: Relation,
        modifier: Optional[Modifier] = None,
    ) -> Optional[DirectStatement]:
        statements = self.find_by_subject_and_relation(
            subject_notion, relation, modifier
        )
        for stmt in statements:
            if stmt.complement_notion.id == complement_notion.id:
                return stmt
        return None

    @abstractmethod
    def find_direct_statement(
        self,
        user_id: str,
        agent_id: str,
        subject_notion: Notion,
        relation: Relation,
        complement_notion: Notion,
        modifier: Optional[Modifier] = None,
    ) -> Optional[DirectStatement]:
        pass

    def find_by_captions(
        self,
        agent_id: str,
        captions: List[str],
        max_depth: int = 1,
    ) -> List[DirectStatement]:
        return []