from __future__ import annotations

import threading
import time
import uuid
from typing import Any, Dict, List, Optional


class UserQuestionManager:
    """In-memory manager for blocking model-to-user questions."""

    def __init__(self):
        self._items: Dict[str, Dict[str, Any]] = {}
        self._lock = threading.Lock()

    @staticmethod
    def _normalize_options(options: Any) -> List[Dict[str, str]]:
        if not isinstance(options, list):
            return []
        normalized: List[Dict[str, str]] = []
        seen = set()
        for idx, raw in enumerate(options[:8], start=1):
            if not isinstance(raw, dict):
                continue
            label = str(raw.get("label") or "").strip()
            if not label:
                continue
            option_id = str(raw.get("id") or "").strip() or f"option_{idx}"
            base = option_id
            suffix = 2
            while option_id in seen:
                option_id = f"{base}_{suffix}"
                suffix += 1
            seen.add(option_id)
            item = {
                "id": option_id,
                "label": label[:120],
            }
            desc = str(raw.get("description") or "").strip()
            if desc:
                item["description"] = desc[:500]
            normalized.append(item)
        return normalized

    def create_question(
        self,
        *,
        username: str,
        conversation_id: Optional[str],
        task_id: Optional[str],
        tool_call_id: Optional[str],
        question: str,
        context: Optional[str] = None,
        options: Any = None,
        batch_id: Optional[str] = None,
        batch_index: int = 0,
        batch_total: int = 1,
    ) -> Dict[str, Any]:
        question_id = f"question_{uuid.uuid4().hex}"
        text = str(question or "").strip()
        item = {
            "question_id": question_id,
            "batch_id": batch_id,
            "batch_index": int(batch_index),
            "batch_total": int(batch_total),
            "username": username,
            "conversation_id": conversation_id,
            "task_id": task_id,
            "tool_call_id": tool_call_id,
            "question": text,
            "context": str(context or "").strip(),
            "options": self._normalize_options(options),
            "status": "pending",
            "created_at": time.time(),
            "answered_at": None,
            "answer": None,
        }
        with self._lock:
            self._items[question_id] = item
        return dict(item)

    def get(self, question_id: str) -> Optional[Dict[str, Any]]:
        with self._lock:
            item = self._items.get(question_id)
            return dict(item) if item else None

    def list_pending(self, username: str, conversation_id: Optional[str] = None) -> List[Dict[str, Any]]:
        with self._lock:
            rows = []
            for item in self._items.values():
                if item.get("username") != username:
                    continue
                if item.get("status") != "pending":
                    continue
                if conversation_id and item.get("conversation_id") != conversation_id:
                    continue
                rows.append(dict(item))
            rows.sort(key=lambda x: (x.get("created_at", 0.0), x.get("batch_index", 0)))
            return rows

    def answer(
        self,
        *,
        question_id: str,
        username: str,
        selected_option_id: Optional[str] = None,
        text: Optional[str] = None,
    ) -> Dict[str, Any]:
        clean_option_id = str(selected_option_id or "").strip()
        clean_text = str(text or "").strip()
        if not clean_option_id and not clean_text:
            raise ValueError("回答不能为空")
        with self._lock:
            item = self._items.get(question_id)
            if not item:
                raise KeyError("问题不存在")
            if item.get("username") != username:
                raise PermissionError("无权限回答该问题")
            if item.get("status") != "pending":
                return dict(item)

            selected_option = None
            if clean_option_id:
                for opt in item.get("options") or []:
                    if str(opt.get("id") or "") == clean_option_id:
                        selected_option = dict(opt)
                        break
                if selected_option is None:
                    raise ValueError("选项不存在")

            answer_type = "option_with_text" if selected_option and clean_text else "option" if selected_option else "free_text"
            answer = {
                "type": answer_type,
                "text": clean_text,
            }
            if selected_option:
                answer["selected_option_id"] = selected_option.get("id")
                answer["selected_option_label"] = selected_option.get("label")
                if selected_option.get("description"):
                    answer["selected_option_description"] = selected_option.get("description")
                if not clean_text:
                    answer["text"] = selected_option.get("label") or ""

            item["status"] = "answered"
            item["answered_at"] = time.time()
            item["answer"] = answer
            return dict(item)


def format_user_question_answer(item: Dict[str, Any]) -> str:
    """Return the compact, model-facing result text for an answered question."""
    answer = item.get("answer") if isinstance(item, dict) else None
    if not isinstance(answer, dict):
        return "用户未回答。"
    lines: List[str] = []
    label = str(answer.get("selected_option_label") or "").strip()
    text = str(answer.get("text") or "").strip()
    if label:
        lines.append(f"用户选择：{label}")
        if text and text != label:
            lines.append(f"用户补充：{text}")
    elif text:
        lines.append(f"用户回答：{text}")
    return "\n".join(lines).strip() or "用户未回答。"
