"""L0 用户 prompt 分析器 — 从 UserPromptSubmit 提取高价值 facts

纯正则实现（复用 auto_classify），延迟 <1ms。
orient hook 中调用，source="prompt_l0"。
"""

from __future__ import annotations

import json
import logging
import re

from .auto_classify import classify_category, estimate_confidence, extract_scope

logger = logging.getLogger(__name__)

# 中英文句子分割
_SENTENCE_SPLIT = re.compile(r"[。！？.!?\n]+")

# 低价值类别 — 跳过
_SKIP_CATEGORIES = frozenset({"code", "config"})

# 每次 prompt 最多提取的 facts 数量
_MAX_FACTS_PER_PROMPT = 3

# --- 准入门槛常量 ---

# CJK 字符检测（中日韩统一表意文字基本区 + 扩展 A）
_CJK_RE = re.compile(r"[\u4e00-\u9fff\u3400-\u4dbf]")

# 推测性语言过滤
_SPECULATIVE_RE = re.compile(
    r"\b(?:maybe|might|could|perhaps|probably)\b|(?:可能|或许|也许|大概)",
    re.IGNORECASE,
)

# 额外偏好模式（#149 增强 — 补充 auto_classify 未覆盖的口语化表达）
_EXTRA_PREFERENCE_RE = re.compile(
    r"(?:"
    # 习惯表达
    r"我一般用|我习惯|I\s+usually|I\s+always\s+\w+"
    # 否定偏好
    r"|不要用|别给我|don'?t\s+use|avoid\s+\w+"
    # 长期信号
    r"|from\s+now\s+on|以后都|going\s+forward|今后"
    # 比较结构
    r"|\w+\s+比\s+\w+\s*(?:好|强|快)"
    r"|\w+\s+(?:over|instead\s+of|rather\s+than)\s+\w+"
    r")",
    re.IGNORECASE,
)

# 准入停用词 — 过滤后计算实质内容词数
_ADMISSION_STOPWORDS = frozenset(
    "的 了 在 是 把 被 给 和 与 从 到 也 都 就 对 又 所 而 且 但 或 "
    "a an the is are was were be to of and in for on with that this".split()
)


def extract_from_prompt(
    prompt: str,
    collection: str,
    session_id: str | None,
) -> list[dict]:
    """从用户 prompt 中提取 constraint/preference/decision 等高价值 facts

    Returns:
        fact dict 列表（同 capture._make_fact 格式），最多 _MAX_FACTS_PER_PROMPT 条
    """
    if not prompt or len(prompt.strip()) < 10:
        return []

    # 分析前 2000 字符（#149 扩展 — 偏好表达可能出现在任意位置）
    # 延迟预算：orient 阻塞路径，2000 字符正则 <1ms（已验证）
    text = prompt[:2000]
    sentences = [s.strip() for s in _SENTENCE_SPLIT.split(text) if len(s.strip()) >= 8]

    facts: list[dict] = []
    for sentence in sentences:
        if len(facts) >= _MAX_FACTS_PER_PROMPT:
            break

        category = classify_category(sentence)
        # #149: 额外偏好模式检测（auto_classify 未覆盖的口语化表达）
        if category in _SKIP_CATEGORIES and _EXTRA_PREFERENCE_RE.search(sentence):
            category = "preference"
        if category in _SKIP_CATEGORIES:
            continue

        # --- 准入门槛 ---

        # a) 跳过疑问句
        if sentence.rstrip().endswith(("?", "？")):
            continue

        # b) 跳过推测性语言（不够确定的不存）
        if _SPECULATIVE_RE.search(sentence):
            continue

        # c) 分类别准入
        is_cjk = bool(_CJK_RE.search(sentence))

        if is_cjk:
            # CJK 文本无空格分词 — auto_classify 关键词匹配已是强信号
            # 只需最低字符数门槛（4 个 CJK 字符 ≈ 有实质内容）
            cjk_count = len(_CJK_RE.findall(sentence))
            if cjk_count < 4:
                continue
        elif category in ("constraint", "preference"):
            # English constraint/preference 只要有动作对象即可
            # "never use ORM"、"prefer X over Y" 能通过
            content_words = [
                w for w in sentence.split()
                if len(w) >= 2 and w.lower() not in _ADMISSION_STOPWORDS
            ]
            if len(content_words) < 2:
                continue
        else:
            # English 其他类别要求具体信号（文件路径/backtick/PascalCase）
            has_file = bool(re.search(r'\.\w{1,4}\b', sentence))
            has_code = bool(re.search(r'`\w+`|\w+\(\)', sentence))
            has_specific = bool(re.search(r'[A-Z][a-z]+[A-Z]\w+', sentence))
            if not (has_file or has_code or has_specific):
                continue

        scope = extract_scope(sentence)
        confidence = estimate_confidence(sentence)

        facts.append({
            "assertion": sentence[:200],
            "category": category,
            "collection": collection,
            "session_id": session_id,
            "scope_files": json.dumps(scope.get("scope_files", [])),
            "scope_modules": json.dumps(scope.get("scope_modules", [])),
            "scope_entities": json.dumps(scope.get("scope_entities", [])),
            "confidence": confidence,
            "source": "prompt_l0",
            "status": "active",
            "context_json": json.dumps({"origin": "user_prompt"}, ensure_ascii=False),
        })

    return facts
