"""Commit Message 生成核心逻辑：调用 LLM、解析响应、反馈重新生成。"""

from __future__ import annotations

import re
from typing import Generator

from acm.config import ACMConfig
from acm.llm.base import LLMBase
from acm.prompt import build_system_prompt, build_user_prompt


class GenerateError(Exception):
    """生成 commit message 时的错误。"""


def _clean_message(raw: str) -> str:
    """清理 LLM 返回的原始内容，去除 markdown 标记等。"""
    text = raw.strip()
    # 去除可能的 ```commit 或 ``` 包裹
    text = re.sub(r"^```[\w]*\n?", "", text)
    text = re.sub(r"\n?```$", "", text)
    return text.strip()


class CommitGenerator:
    """Commit message 生成器，支持反馈多次重新生成。"""

    def __init__(self, llm: LLMBase, config: ACMConfig):
        self._llm = llm
        self._config = config
        self._system_prompt: str = ""
        self._history: list[dict[str, str]] = []

    def generate(self, diff_content: str) -> str:
        """首次生成 commit message。

        Args:
            diff_content: git diff 内容（可能已截断）。

        Returns:
            生成的 commit message。
        """
        self._system_prompt = build_system_prompt(self._config, diff_content=diff_content)
        user_prompt = build_user_prompt(diff_content)
        self._history = [{"role": "user", "content": user_prompt}]

        raw = self._llm.chat(self._system_prompt, user_prompt)
        if not raw:
            raise GenerateError("LLM 返回了空内容，请检查模型配置")

        message = _clean_message(raw)
        self._history.append({"role": "assistant", "content": message})
        return message

    def stream_generate(self, diff_content: str) -> Generator[str, None, str]:
        """流式首次生成，逐块 yield 内容，最终 return 完整 message。

        用法::

            gen = generator.stream_generate(diff)
            try:
                while True:
                    chunk = next(gen)
                    # 实时显示 chunk
            except StopIteration as e:
                final_message = e.value
        """
        self._system_prompt = build_system_prompt(self._config, diff_content=diff_content)
        user_prompt = build_user_prompt(diff_content)
        self._history = [{"role": "user", "content": user_prompt}]

        chunks: list[str] = []
        for chunk in self._llm.stream_chat(self._system_prompt, user_prompt):
            chunks.append(chunk)
            yield chunk

        raw = "".join(chunks)
        if not raw:
            raise GenerateError("LLM 返回了空内容，请检查模型配置")

        message = _clean_message(raw)
        self._history.append({"role": "assistant", "content": message})
        return message

    def stream_regenerate(self, feedback: str) -> Generator[str, None, str]:
        """流式反馈重新生成，逐块 yield 内容，最终 return 完整 message。"""
        feedback_prompt = f"用户对上一次生成结果的反馈：{feedback}\n请根据反馈重新生成 commit message。"
        self._history.append({"role": "user", "content": feedback_prompt})

        chunks: list[str] = []
        for chunk in self._llm.stream_chat_with_history(self._system_prompt, self._history):
            chunks.append(chunk)
            yield chunk

        raw = "".join(chunks)
        if not raw:
            raise GenerateError("LLM 返回了空内容，请检查模型配置")

        message = _clean_message(raw)
        self._history.append({"role": "assistant", "content": message})
        return message

    def regenerate(self, feedback: str) -> str:
        """根据用户反馈重新生成（非流式）。

        Args:
            feedback: 用户的反馈意见。

        Returns:
            重新生成的 commit message。
        """
        feedback_prompt = f"用户对上一次生成结果的反馈：{feedback}\n请根据反馈重新生成 commit message。"
        self._history.append({"role": "user", "content": feedback_prompt})

        raw = self._llm.chat_with_history(self._system_prompt, self._history)
        if not raw:
            raise GenerateError("LLM 返回了空内容，请检查模型配置")

        message = _clean_message(raw)
        self._history.append({"role": "assistant", "content": message})
        return message

    @property
    def history(self) -> list[dict[str, str]]:
        """返回当前对话历史（只读）。"""
        return list(self._history)
