from typing import Union
import json

from analogai.deepthink.presentation.presenters.utils.plural_utils import get_plural_relationship
from analogai.deepthink.presentation.presenters.utils.list_format_utils import (
    format_items_and,
    format_items_and_capitalized,
)


def _normalize_relation_value(relation: Union[str, "Relation", "RelationshipType"]) -> "Relation":
    from analogai.foundation.common.enums import RelationshipType
    from analogai.foundation.core.value_objects.relation import Relation

    if isinstance(relation, Relation):
        return relation
    if isinstance(relation, RelationshipType):
        return Relation.from_type(relation)
    if isinstance(relation, str):
        return Relation.from_string(relation)
    raise ValueError("relation must be a Relation, RelationshipType, or string")


def format_single_belief_statement(
    subject_notion_caption: Union[str, "NotionExpression"],
    complement_notion_caption: Union[str, "NotionExpression"],
    relation: Union[str, "Relation", "RelationshipType"],
    probability: float = 1.0,
    modifier=None,
    timezone=None,
) -> str:
    from analogai.foundation.common.dtos.belief_expression import BeliefExpression
    from analogai.foundation.common.dtos.notion_expression import NotionExpression
    from analogai.foundation.common.utils.expressions_serializer import serialize_belief_expression

    relation_value = _normalize_relation_value(relation)
    subject_expr = (
        subject_notion_caption
        if isinstance(subject_notion_caption, NotionExpression)
        else NotionExpression(subject_notion_caption)
    )
    complement_expr = (
        complement_notion_caption
        if isinstance(complement_notion_caption, NotionExpression)
        else NotionExpression(complement_notion_caption)
    )
    expression = BeliefExpression(
        subject_notion_expression=subject_expr,
        complement_notion_expression=complement_expr,
        relation=relation_value,
        probability=probability,
        validity=1.0,
        modifier=modifier,
    )
    return serialize_belief_expression(expression, timezone=timezone)


def build_modifier_signature(modifier) -> str | None:
    if modifier is None:
        return None

    data = None
    if hasattr(modifier, "model_dump"):
        try:
            data = modifier.model_dump(exclude_none=True)
        except TypeError:
            data = modifier.model_dump()
    elif hasattr(modifier, "dict"):
        try:
            data = modifier.dict(exclude_none=True)
        except TypeError:
            data = modifier.dict()
    elif hasattr(modifier, "__dict__"):
        data = modifier.__dict__

    if isinstance(data, dict):
        return json.dumps(data, sort_keys=True, default=str)

    return str(modifier)


def format_grouped_statement(
    common_notion: str,
    relation: str,
    other_notions: list[str],
    is_subject_grouped: bool,
    modifier=None,
    timezone=None,
) -> str:
    from analogai.foundation.common.utils.statement_serializers import serialize_statement

    if not other_notions:
        other_notions = []
    else:
        seen = set()
        deduped = []
        for item in other_notions:
            if item in seen:
                continue
            seen.add(item)
            deduped.append(item)
        other_notions = deduped

    if len(other_notions) == 1:
        if is_subject_grouped:
            return serialize_statement(
                subject_notion_caption=common_notion,
                complement_notion_caption=other_notions[0],
                relation=relation,
                probability=1.0,
                modifier=modifier,
                timezone=timezone,
            )
        return serialize_statement(
            subject_notion_caption=other_notions[0],
            complement_notion_caption=common_notion,
            relation=relation,
            probability=1.0,
            modifier=modifier,
            timezone=timezone,
        )

    combined = format_items_and(other_notions)
    plural_relationship = get_plural_relationship(relation)

    if is_subject_grouped:
        return f"{common_notion.capitalize()} {plural_relationship} {combined}"
    sources_combined = format_items_and_capitalized(other_notions)
    return f"{sources_combined} {plural_relationship} {common_notion.capitalize()}"
