from __future__ import annotations

import json
from typing import Any, Dict, List, Optional

from core.config import META_KEY
from core.tool import tool, tool_func
from core.tools.segment_llm import LLMTool
from loguru import logger


FACT_MERGER_SYSTEM_PROMPT = """
你将收到同一个 summary_name 下，从多个合同分段提取出的 facts 列表。

你的任务是做事实合并，而不是审查或推断：
1. 仅基于输入 facts 合并信息，不得新增输入中不存在的事实。
2. 去除重复、空值和无意义的“未明确”信息；如果全部都是“未明确”，保留“未明确”。
3. 保留关键条件、金额、比例、期限、主体、触发条件等具体信息。
4. 当多个分段信息互补时，合并为结构化对象或对象列表。
5. 当信息存在明显冲突且无法判断真伪时，同时保留并标注为不同表述，不要自行裁决。
6. 严格输出 JSON。
"""

FACT_MERGER_USER_PROMPT = """
summary_name:
{summary_name}

facts:
{facts}

请输出 JSON，格式如下：
"""

OUTPUT_EXAMPLE = """
```json
{
  "value": {
    "合并后的字段": "合并后的事实"
  }
}
```
"""


def _normalize_summary_names(summary_names: Optional[List[str]]) -> List[str]:
    names: List[str] = []
    seen = set()
    for name in summary_names or []:
        text = str(name or "").strip()
        if not text or text in seen:
            continue
        seen.add(text)
        names.append(text)
    return names


def _is_empty_fact_value(value: Any) -> bool:
    if value is None:
        return True
    if isinstance(value, str):
        return not value.strip()
    if isinstance(value, dict):
        return not value
    if isinstance(value, list):
        return not value
    return False


def _dedupe_values(values: List[Any]) -> List[Any]:
    unique: List[Any] = []
    seen = set()
    for value in values:
        if _is_empty_fact_value(value):
            continue
        try:
            marker = json.dumps(value, ensure_ascii=False, sort_keys=True)
        except TypeError:
            marker = str(value)
        if marker in seen:
            continue
        seen.add(marker)
        unique.append(value)
    return unique


def _extract_fact_values(
    facts: List[Dict[str, Any]], summary_names: List[str]
) -> Dict[str, List[Any]]:
    grouped = {name: [] for name in summary_names}
    for item in facts or []:
        if not isinstance(item, dict):
            continue
        for name in summary_names:
            if name in item:
                grouped[name].append(item.get(name))
    return {name: _dedupe_values(values) for name, values in grouped.items()}


def _deterministic_merge(values: List[Any]) -> Any:
    unique_values = _dedupe_values(values)
    if not unique_values:
        return {}
    if len(unique_values) == 1:
        return unique_values[0]
    return unique_values


@tool("fact_merger", "同 summary_name facts 合并")
class FactMergerTool(LLMTool):
    def __init__(self) -> None:
        super().__init__(FACT_MERGER_SYSTEM_PROMPT)

    @tool_func(
        {
            "type": "object",
            "properties": {
                "facts": {"type": "array", "items": {"type": "object"}},
                "summary_names": {"type": "array", "items": {"type": "string"}},
                "merge_mode": {
                    "type": "string",
                    "enum": ["llm", "rule"],
                    "default": "llm",
                },
            },
            "required": ["facts", "summary_names"],
        }
    )
    def run(
        self,
        facts: List[Dict[str, Any]],
        summary_names: List[str],
        merge_mode: str = "llm",
    ) -> Dict[str, Any]:
        names = _normalize_summary_names(summary_names)
        if not names:
            return {"merge_facts": {}}

        grouped = _extract_fact_values(facts, names)
        merged: Dict[str, Any] = {}
        for name in names:
            values = grouped.get(name, [])
            if not values:
                continue
            merged[name] = self._merge_values(name, values, merge_mode)

        merged[META_KEY] = {
            "summary_names": names,
            "source_fact_count": len(facts or []),
        }
        return {"merge_facts": merged}

    def _merge_values(self, summary_name: str, values: List[Any], merge_mode: str) -> Any:
        unique_values = _dedupe_values(values)
        if len(unique_values) <= 1:
            return unique_values[0] if unique_values else {}
        if str(merge_mode or "llm").lower() != "llm":
            return _deterministic_merge(unique_values)
        try:
            return self._merge_values_with_llm(summary_name, unique_values)
        except Exception as exc:
            logger.error("LLM fact merge failed, fallback to rule merge: %s", exc)
            return _deterministic_merge(unique_values)

    def _merge_values_with_llm(self, summary_name: str, values: List[Any]) -> Any:
        user_content = (
            FACT_MERGER_USER_PROMPT.format(
                summary_name=summary_name,
                facts=json.dumps(values, ensure_ascii=False, indent=2),
            )
            + OUTPUT_EXAMPLE
        )
        msgs = self.build_messages(user_content)
        resp = self.run_with_loop(self.chat_async(msgs))
        data = self.parse_first_json(resp)
        if "value" not in data:
            raise ValueError("missing value in fact merge response")
        return data.get("value")
