"""
Variable Extractor for Intent-Driven Script Flow.
从用户输入中提取期望变量，如年级、学科等。
"""

import asyncio
import logging
import re
from typing import Any

logger = logging.getLogger(__name__)


VARIABLE_PATTERNS = {
    "grade": [
        (r"初[一二三]", lambda m: m.group(0)),
        (r"高[一二三]", lambda m: m.group(0)),
        (r"七年级", lambda m: "初一"),
        (r"八年级", lambda m: "初二"),
        (r"九年级", lambda m: "初三"),
        (r"高一", lambda m: "高一"),
        (r"高二", lambda m: "高二"),
        (r"高三", lambda m: "高三"),
    ],
    "subject": [
        (r"语文", lambda m: "语文"),
        (r"数学", lambda m: "数学"),
        (r"英语|英文", lambda m: "英语"),
        (r"物理", lambda m: "物理"),
        (r"化学", lambda m: "化学"),
        (r"生物", lambda m: "生物"),
        (r"历史", lambda m: "历史"),
        (r"地理", lambda m: "地理"),
        (r"政治", lambda m: "政治"),
    ],
}


class VariableExtractor:
    """
    变量提取器
    从用户输入中提取期望变量（如年级、学科等）
    
    支持两种模式:
    1. 规则匹配: 使用预定义的正则表达式匹配
    2. LLM 提取: 使用大语言模型智能提取
    """

    DEFAULT_TIMEOUT = 5.0

    def __init__(self, llm_client: Any = None):
        """
        Initialize VariableExtractor.

        Args:
            llm_client: LLM client for intelligent extraction (optional)
        """
        self._llm_client = llm_client

    async def extract(
        self,
        user_input: str,
        expected_variables: list[str],
        history: list[dict[str, str]] | None = None,
    ) -> dict[str, str]:
        """
        从用户输入中提取期望变量

        Args:
            user_input: 用户输入文本
            expected_variables: 期望提取的变量列表，如 ["grade", "subject"]
            history: 对话历史（用于 LLM 提取时的上下文）

        Returns:
            提取的变量字典，如 {"grade": "初一", "subject": "语文"}
        """
        if not expected_variables:
            return {}

        result = {}

        for var_name in expected_variables:
            value = await self._extract_variable(
                variable_name=var_name,
                user_input=user_input,
                history=history,
            )
            if value:
                result[var_name] = value

        if result:
            logger.info(f"[VariableExtractor] Extracted variables: {result}")

        return result

    async def _extract_variable(
        self,
        variable_name: str,
        user_input: str,
        history: list[dict[str, str]] | None,
    ) -> str | None:
        """
        提取单个变量

        先尝试规则匹配，失败则使用 LLM 提取
        """
        value = self._extract_by_pattern(variable_name, user_input)
        if value:
            return value

        if self._llm_client:
            value = await self._extract_by_llm(variable_name, user_input, history)
            if value:
                return value

        return None

    def _extract_by_pattern(self, variable_name: str, user_input: str) -> str | None:
        """
        使用正则表达式提取变量
        """
        patterns = VARIABLE_PATTERNS.get(variable_name, [])
        for pattern, extractor in patterns:
            match = re.search(pattern, user_input)
            if match:
                return extractor(match)
        return None

    async def _extract_by_llm(
        self,
        variable_name: str,
        user_input: str,
        history: list[dict[str, str]] | None,
    ) -> str | None:
        """
        使用 LLM 提取变量
        """
        prompt = self._build_extraction_prompt(variable_name, user_input, history)

        try:
            messages = [{"role": "user", "content": prompt}]
            response = await asyncio.wait_for(
                self._llm_client.generate(messages),
                timeout=self.DEFAULT_TIMEOUT,
            )
            value = response.content.strip() if hasattr(response, 'content') else str(response).strip()
            
            if value and value not in ["未知", "无法确定", "无", "None", "null"]:
                return value

        except asyncio.TimeoutError:
            logger.warning(
                f"[VariableExtractor] LLM extraction timeout for {variable_name}"
            )
        except Exception as e:
            logger.warning(
                f"[VariableExtractor] LLM extraction failed for {variable_name}: {e}"
            )

        return None

    def _build_extraction_prompt(
        self,
        variable_name: str,
        user_input: str,
        history: list[dict[str, str]] | None,
    ) -> str:
        """
        构建变量提取的提示词
        """
        variable_descriptions = {
            "grade": "年级（如：初一、初二、初三、高一、高二、高三）",
            "subject": "学科（如：语文、数学、英语、物理、化学、生物）",
            "type": "内容类型（如：痛点、学科特点、能力要求、课程价值、观点）",
        }

        description = variable_descriptions.get(variable_name, variable_name)

        prompt_parts = [
            f'请从以下用户输入中提取"{description}"信息。',
            "",
            f"用户输入：{user_input}",
            "",
        ]

        if history:
            prompt_parts.append("对话历史：")
            for msg in history[-3:]:
                role = "用户" if msg.get("role") == "user" else "客服"
                content = msg.get("content", "")
                prompt_parts.append(f"{role}: {content}")
            prompt_parts.append("")

        prompt_parts.extend([
            "要求：",
            "1. 如果能确定，直接返回提取的值（如：初一、语文）",
            "2. 如果无法确定，返回\"未知\"",
            "3. 只返回提取的值，不要解释",
        ])

        return "\n".join(prompt_parts)
