from __future__ import annotations

import json
from typing import Iterable, List, Optional

from analogai.deepthink.presentation.parsers.parsed_sentence import ParsedSentence
from analogai.deepthink.presentation.parsers.parsed_sentence_extractor import parse_sentences


class JsonPayloadParser:
    def parse(self, json_str: str) -> Optional[dict]:
        try:
            return json.loads(json_str.strip())
        except json.JSONDecodeError:
            return None


class SentenceDataExtractor:
    def extract(self, data: dict) -> List[dict]:
        if "sentences" in data:
            sentence_payloads = _as_list(data.get("sentences"))
            return sentence_payloads if sentence_payloads else []
        if "intent" in data or "intent_type" in data:
            return [data]
        return []


class ConditionTransformer:
    def __init__(self, accessor: "MappingAccessor" | None = None) -> None:
        self._accessor = accessor or MappingAccessor()

    def transform(self, sentence_data: dict) -> dict:
        condition = self._accessor.as_dict(sentence_data.get("condition"))
        if not condition:
            return sentence_data
        builder = ConditionPhraseBuilder(self._accessor)
        location = condition.get("location")
        cause_phrase = builder.build_phrase(
            base="condition",
            data=condition,
            predicate=condition.get("predicate"),
            subject_keys=("subject", "subject_caption"),
            relation_keys=("relationship", "relation", "relation_name", "relationship_phrase"),
            complement_keys=("object", "complement", "complement_caption"),
            location=location,
        )

        effect_phrase = builder.build_phrase(
            base="effect",
            data=sentence_data,
            predicate=sentence_data.get("predicate"),
            subject_keys=("subject", "subject_caption"),
            relation_keys=("relationship", "relation", "relation_name", "relationship_phrase"),
            complement_keys=("object", "complement", "complement_caption"),
        )

        result = {
            "intent_type": "making_hypothetical_statement" if location else "making_statement",
            "subject": cause_phrase.strip(),
            "predicate": {
                "relation": "causes",
                "complement": effect_phrase.strip(),
            },
        }

        for key in ("cause_subject", "cause_location", "effect_subject", "effect_location"):
            if key in sentence_data and sentence_data[key]:
                result[key] = sentence_data[key]

        return result


class ParsedSentenceExtractor:
    def extract(self, sentence_data: dict) -> List[ParsedSentence]:
        return parse_sentences({"sentences": [sentence_data]})


class MessageParsingPipeline:
    def __init__(
        self,
        payload_parser: JsonPayloadParser | None = None,
        data_extractor: SentenceDataExtractor | None = None,
        condition_transformer: ConditionTransformer | None = None,
        sentence_extractor: ParsedSentenceExtractor | None = None,
    ) -> None:
        self._payload_parser = payload_parser or JsonPayloadParser()
        self._data_extractor = data_extractor or SentenceDataExtractor()
        self._condition_transformer = condition_transformer or ConditionTransformer()
        self._sentence_extractor = sentence_extractor or ParsedSentenceExtractor()

    def parse(self, json_str: str) -> List[ParsedSentence]:
        payload = self._payload_parser.parse(json_str)
        if payload is None:
            return []
        sentence_payloads = self._data_extractor.extract(payload)
        result: List[ParsedSentence] = []
        for sentence_payload in sentence_payloads:
            payload_dict = _as_dict(sentence_payload)
            if payload_dict is None:
                continue
            transformed = self._condition_transformer.transform(payload_dict)
            result.extend(self._sentence_extractor.extract(transformed))
        return result


def _as_list(value) -> Optional[list]:
    return value if isinstance(value, list) else None


def _as_dict(value) -> Optional[dict]:
    return value if isinstance(value, dict) else None


class MappingAccessor:
    def as_dict(self, value) -> Optional[dict]:
        return value if isinstance(value, dict) else None

    def get_first(self, data: dict, keys: Iterable[str]) -> Optional[str]:
        for key in keys:
            candidate = data.get(key)
            if candidate:
                return candidate
        return None


class ConditionPhraseBuilder:
    def __init__(self, accessor: MappingAccessor) -> None:
        self._accessor = accessor

    def build_phrase(
        self,
        base: str,
        data: dict,
        predicate,
        subject_keys: Iterable[str],
        relation_keys: Iterable[str],
        complement_keys: Iterable[str],
        location: Optional[str] = None,
    ) -> str:
        subject = self._accessor.get_first(data, subject_keys)
        predicate_payload = self._accessor.as_dict(predicate) or {}
        relation = (
            predicate_payload.get("relation")
            or self._accessor.get_first(data, relation_keys)
        )
        complement = (
            predicate_payload.get("complement_caption")
            or predicate_payload.get("complement")
            or self._accessor.get_first(data, complement_keys)
        )
        parts = [str(p) for p in (subject, relation, complement) if p]
        phrase = " ".join(parts) if parts else base
        if location:
            phrase = f"{phrase} in {location}"
        return phrase
