"""反馈学习模块：记录用户反馈，按相似度匹配注入 prompt，动态优化后续生成。"""

from __future__ import annotations

import json
import re
from dataclasses import asdict, dataclass
from pathlib import Path

from acm.config import GLOBAL_CONFIG_DIR

FEEDBACK_FILE = GLOBAL_CONFIG_DIR / "feedback.json"
MAX_FEEDBACK_RECORDS = 20
MAX_INJECT_RECORDS = 5


@dataclass
class FeedbackRecord:
    """一条反馈记录。"""
    original_message: str   # LLM 原始生成的 message
    feedback: str           # 用户的反馈内容
    improved_message: str   # 改进后的 message


def load_feedback(path: Path | None = None) -> list[FeedbackRecord]:
    """加载历史反馈记录。"""
    fp = path or FEEDBACK_FILE
    if not fp.is_file():
        return []
    try:
        with open(fp, "r", encoding="utf-8") as f:
            data = json.load(f)
        return [
            FeedbackRecord(
                original_message=r["original_message"],
                feedback=r["feedback"],
                improved_message=r["improved_message"],
            )
            for r in data
        ]
    except (json.JSONDecodeError, KeyError, TypeError):
        return []


def save_feedback(records: list[FeedbackRecord], path: Path | None = None) -> None:
    """保存反馈记录到文件。"""
    fp = path or FEEDBACK_FILE
    fp.parent.mkdir(parents=True, exist_ok=True)
    data = [asdict(r) for r in records]
    with open(fp, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)


def add_feedback(
    original_message: str,
    feedback: str,
    improved_message: str,
    path: Path | None = None,
) -> None:
    """添加一条反馈记录，超过上限时淘汰最早的记录。"""
    records = load_feedback(path)
    records.append(FeedbackRecord(
        original_message=original_message,
        feedback=feedback,
        improved_message=improved_message,
    ))
    # 保留最近 N 条
    if len(records) > MAX_FEEDBACK_RECORDS:
        records = records[-MAX_FEEDBACK_RECORDS:]
    save_feedback(records, path)


def clear_feedback(path: Path | None = None) -> int:
    """清空所有反馈记录，返回清除的条数。"""
    fp = path or FEEDBACK_FILE
    records = load_feedback(fp)
    count = len(records)
    if fp.is_file():
        fp.unlink()
    return count


def _parse_type_scope(message: str) -> tuple[str, set[str]]:
    """从 commit message 中提取 type 和 scope 集合。

    例如 'feat(auth, api): 描述' -> ('feat', {'auth', 'api'})
    """
    m = re.match(r"^(\w+)\(([^)]*)\)", message)
    if not m:
        return ("", set())
    msg_type = m.group(1)
    scopes = {s.strip() for s in m.group(2).split(",") if s.strip()}
    return (msg_type, scopes)


def match_feedback(
    diff_content: str,
    records: list[FeedbackRecord] | None = None,
    path: Path | None = None,
    max_results: int = MAX_INJECT_RECORDS,
) -> list[FeedbackRecord]:
    """从历史反馈中筛选与当前 diff 最相关的记录。

    匹配策略（按优先级）：
    1. 反馈内容中的关键词在 diff 中出现 -> 高相关
    2. improved_message 的 type 在 diff 路径中能推断 -> 中相关
    3. 兜底：最近的记录优先

    Args:
        diff_content: 当前的 diff 内容。
        records: 反馈记录列表，None 时从文件加载。
        path: 反馈文件路径。
        max_results: 最多返回的条数。

    Returns:
        筛选后的反馈记录列表。
    """
    if records is None:
        records = load_feedback(path)
    if not records:
        return []

    diff_lower = diff_content.lower()

    scored: list[tuple[float, int, FeedbackRecord]] = []
    for idx, r in enumerate(records):
        score = 0.0

        # 策略1：反馈关键词出现在 diff 中
        feedback_words = set(re.findall(r"[\w\u4e00-\u9fff]+", r.feedback.lower()))
        for word in feedback_words:
            if len(word) >= 2 and word in diff_lower:
                score += 2.0

        # 策略2：improved_message 的 scope 出现在 diff 路径中
        _, scopes = _parse_type_scope(r.improved_message)
        for scope in scopes:
            if scope.lower() in diff_lower:
                score += 1.5

        # 策略3：recency bonus（越新的记录分数越高）
        score += idx * 0.1

        scored.append((score, idx, r))

    # 按分数降序排列
    scored.sort(key=lambda x: x[0], reverse=True)
    return [r for _, _, r in scored[:max_results]]
