from __future__ import annotations

from dataclasses import dataclass

from sqlalchemy import select
from sqlalchemy.orm import Session

from app.models.ai_config import Prompt
from app.models.chat import ChatMessage
from app.models.user import User
from app.services.feishu_service import FeishuKnowledgeService
from app.services.knowledge_service import KnowledgeAccessService, KnowledgeScope

NO_HIT_ANSWER = "当前知识库中未检索到相关内容，请联系管理员补充相关知识。"

# 摘要配置：超过 KEEP_RECENT 轮的历史会被压缩成摘要
KEEP_RECENT = 5
# 触发摘要的轮数阈值（当历史总轮数 > 这个值时才触发）
SUMMARY_TRIGGER_ROUNDS = 8


@dataclass(frozen=True)
class RetrievedChunk:
    knowledge_id: int
    knowledge_name: str
    title: str
    content: str
    source_url: str | None = None


@dataclass(frozen=True)
class RagResult:
    question: str
    knowledge_scopes: list[KnowledgeScope]
    chunks: list[RetrievedChunk]
    prompt: str

    @property
    def is_hit(self) -> bool:
        return len(self.chunks) > 0

    @property
    def knowledge_ids(self) -> str:
        return ",".join(str(scope.id) for scope in self.knowledge_scopes)


class RagService:
    @staticmethod
    def build_result(
        db: Session,
        user: User,
        question: str,
        history: list[ChatMessage] | None = None,
        session_summary: str | None = None,
    ) -> RagResult:
        scopes = KnowledgeAccessService.get_allowed_knowledge(db, user)
        chunks = FeishuKnowledgeService.retrieve(question, scopes, db)
        prompt = PromptService.build_prompt(db, question, chunks, history, session_summary)
        return RagResult(question=question, knowledge_scopes=scopes, chunks=chunks, prompt=prompt)


class PromptService:
    _default_prompt = (
        "你是大本营答疑助手。你只能基于提供的知识片段回答，不能编造。"
        "如果知识片段之间有冲突，需要说明不同来源的观点。"
    )

    @classmethod
    def build_prompt(
        cls,
        db: Session,
        question: str,
        chunks: list[RetrievedChunk],
        history: list[ChatMessage] | None = None,
        session_summary: str | None = None,
    ) -> str:
        prompt = cls._load_active_prompt(db)

        # 知识库上下文
        context = "\n\n".join(
            f"[知识片段 {index}] 来源：{chunk.knowledge_name} / {chunk.title}\n{chunk.content}"
            for index, chunk in enumerate(chunks, start=1)
        )
        if not context:
            context = "未检索到相关知识片段。"

        parts = [prompt]

        # 对话历史：摘要 + 最近 N 轮原文
        history_part = cls._build_history_section(history, session_summary)
        if history_part:
            parts.append(history_part)

        parts.append(context)
        parts.append(f"用户问题：{question.strip()}")

        return "\n\n".join(parts)

    @classmethod
    def _build_history_section(
        cls,
        history: list[ChatMessage] | None,
        session_summary: str | None,
    ) -> str:
        if not history:
            return ""

        lines: list[str] = []

        # 如果有历史摘要，先放摘要
        if session_summary:
            lines.append(f"[历史对话摘要]\n{session_summary}")

        # 只保留最近 KEEP_RECENT 轮的原文（1 轮 = 1 个 user + 1 个 assistant）
        recent = history[-(KEEP_RECENT * 2):]
        if recent:
            role_labels = {"user": "用户", "assistant": "大本营答疑助手"}
            for msg in recent:
                label = role_labels.get(msg.role, msg.role)
                content = msg.content.strip()
                # 去掉 think 标签，不需要在历史中重复传递
                import re
                content = re.sub(r"<think[\s\S]*?</think\s*>", "", content, flags=re.IGNORECASE).strip()
                if content:
                    lines.append(f"{label}：{content}")

        return "[对话历史]\n" + "\n".join(lines) if lines else ""

    @classmethod
    def _load_active_prompt(cls, db: Session) -> str:
        prompt = db.scalar(
            select(Prompt)
            .order_by(Prompt.updated_at.desc(), Prompt.id.desc())
            .limit(1)
        )
        return prompt.prompt_content if prompt else cls._default_prompt
