"""ResponseAction — 최종 응답 생성 (코어 내장).

AgentQueue 파이프라인의 마지막 ActionSet(Response)에서 단독 실행.
전체 context를 종합하여 사용자 응답을 LLM 스트리밍으로 생성한다.
설계 문서: §4.6
"""

from __future__ import annotations

from typing import AsyncGenerator

from oedix.core.action import Action, ActionOutput
from oedix.core.context import Context, ContextType
from oedix.core.events import Event, EventType

# ------------------------------------------------------------------
# System prompt for response generation
# ------------------------------------------------------------------

_RESPONSE_SYSTEM_PROMPT = """\
You are an AI assistant generating a final response to the user.

## Core Rules
- Use the same language as the user's original request.
- Do NOT mention internal processes, action names, or pipeline details.
- If there were issues or partial failures, mention them honestly.

## Response Style — Adapt by Request Type

First, classify the user's request into one of these categories, then \
apply the corresponding format:

### 1. Information Request (정보 요청)
Factual questions, lookups, searches, data queries.
→ Deliver the answer directly and concisely. No verbose framing. \
Lead with the key fact or number, then add brief supporting details \
only if they add value. Avoid unnecessary headings or bullet lists \
for simple answers.

### 2. Report / Analysis Request (보고 / 분석)
Business reports, comparisons, trend analysis, status summaries.
→ Use a structured report format with clear headings, bullet points, \
and data-driven conclusions. Include key metrics, dates, and sources. \
End with a brief summary or recommendation if appropriate.

### 3. Creative / Writing Request (창작 / 작문)
Stories, essays, copywriting, brainstorming, naming, etc.
→ Match the requested tone and style. Prioritize originality and \
readability. Do not over-explain the creative process — deliver the \
creative output directly.

### 4. Task Execution with Artifacts (작업 수행 결과)
If files were created, code was written, configurations were changed, \
or any tangible work artifacts were produced during the process:
→ Provide a concise summary report of what was done:
  - What was requested
  - What actions were taken
  - List of created/modified artifacts (file paths, names, etc.)
  - Final status or result
This applies regardless of the original request category — if work \
artifacts exist in the context, always include the summary report.

### 5. Action / Execution Request (실행 요청)
"Do X", "Run Y", "Set up Z" — requests to perform an action.
→ Confirm what was done, show the result, and note any next steps \
if applicable. Be concise.

## Synthesis
Combine ALL relevant context (action results, tool outputs, gathered \
data) into the response. Do not omit important findings."""


class ResponseAction(Action):
    """최종 응답 생성 Action.

    ActionSet(Response)에서 단독 실행되며, thinking 없이
    context를 기반으로 사용자 최종 응답을 스트리밍 생성한다.
    후속 Action이나 ActionSet을 추가하지 않는 종결 Action.
    """

    type = "response"

    async def execute(
        self, context: list[Context]
    ) -> AsyncGenerator[Event, None]:
        # Phase 1: 컨텍스트 정리 — 메시지 구성
        messages = self._build_messages(context)

        # Phase 2: LLM 스트리밍 응답 생성
        result_parts: list[str] = []
        async for chunk in self.call_llm(messages):
            result_parts.append(chunk)
            yield self.emit(EventType.RESPONSE, {"content": chunk})

        # Phase 3: 완료 — ActionOutput 저장
        result_text = "".join(result_parts)
        if not result_text.strip():
            result_text = self._fallback(context)
            if result_text:
                yield self.emit(EventType.RESPONSE, {"content": result_text})

        self.output = ActionOutput(
            result=result_text,
            summary=f"최종 응답: {result_text[:200]}",
        )

    def describe(self) -> str:
        return "전체 컨텍스트를 종합하여 최종 사용자 응답 생성"

    # ------------------------------------------------------------------
    # Internal helpers
    # ------------------------------------------------------------------

    def _build_messages(self, context: list[Context]) -> list[dict]:
        """Build LLM messages from the context list."""
        messages: list[dict] = [
            {"role": "system", "content": _RESPONSE_SYSTEM_PROMPT},
        ]

        user_query = ""
        context_parts: list[str] = []

        for ctx in context:
            if ctx.type == ContextType.USER_QUERY:
                user_query = ctx.content
            elif ctx.type == ContextType.SYSTEM:
                messages[0]["content"] = (
                    ctx.content + "\n\n" + _RESPONSE_SYSTEM_PROMPT
                )
            elif ctx.type == ContextType.INSTRUCTION:
                context_parts.append(f"[Instruction]\n{ctx.content}")
            elif ctx.type in (
                ContextType.ACTION_RESULT,
                ContextType.TOOL_OUTPUT,
            ):
                context_parts.append(f"[{ctx.type.value}]\n{ctx.content}")
            elif ctx.type == ContextType.SUMMARY:
                context_parts.append(f"[Summary]\n{ctx.content}")

        # Assemble user message
        user_content = ""
        if context_parts:
            user_content += (
                "## Work Context\n\n"
                + "\n\n".join(context_parts)
                + "\n\n"
            )
        if user_query:
            user_content += (
                "## User Query\n\n"
                + user_query
                + "\n\n"
                + "Based on all the above context, provide a comprehensive response."
            )
        else:
            user_content += "Provide a response based on the above context."

        messages.append({"role": "user", "content": user_content})
        return messages

    def _fallback(self, context: list[Context]) -> str:
        """Generate a fallback response when LLM returns empty."""
        results = [
            ctx.content
            for ctx in context
            if ctx.type
            in (ContextType.ACTION_RESULT, ContextType.TOOL_OUTPUT)
        ]
        if results:
            summary = "\n".join(
                f"- {r[:500]}" for r in results[:10]
            )
            return f"## 작업 결과 요약\n\n{summary}"
        return "작업이 완료되었습니다."
