import uuid
from abc import ABC, abstractmethod
from typing import Optional, Any

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
from analogai.foundation.common.utils.entity_formatters import format_statement_str


class StatementBase(ABC):
    

    def __init__(
        self,
        agent_id: str,
        subject_notion: Notion,
        complement_notion: Notion,
        relation: Relation,
        id: Optional[str] = None,
        modifier: Optional[Modifier] = None,
    ):
        if not agent_id:
            raise ValueError("agent_id must be a non-empty string")
        if subject_notion is None:
            raise ValueError("subject_notion cannot be None")
        if complement_notion is None:
            raise ValueError("complement_notion cannot be None")
        if relation is None:
            raise ValueError("relation cannot be None")
        if not isinstance(relation, Relation):
            raise TypeError("relation must be a Relation instance")

        self.id = id if id else str(uuid.uuid4())
        self.agent_id = agent_id
        self.subject_notion = subject_notion
        self.complement_notion = complement_notion
        self.relation = relation
        self.modifier: Optional[Modifier] = modifier

    @property
    @abstractmethod
    def probability(self) -> float:
        
        pass

    @property
    @abstractmethod
    def validity(self) -> float:
        
        pass

    @property
    def location(self) -> Optional[str]:
        return self.modifier.location if self.modifier else None

    @property
    def from_time(self):
        return self.modifier.from_time if self.modifier else None

    @property
    def to_time(self):
        return self.modifier.to_time if self.modifier else None

    @property
    def deontic_modality(self):
        return self.modifier.deontic_modality if self.modifier else None

    @property
    def quantity(self) -> Optional[float]:
        return self.modifier.quantity if self.modifier else None

    @abstractmethod
    def visit(self, visitor: Any) -> Any:
        
        pass


    def __str__(self) -> str:
        return format_statement_str(self)