from __future__ import annotations

import json
from dataclasses import dataclass

from .models import TaskState


@dataclass
class PlannerDecision:
    summary: str
    command: str | None = None
    title: str | None = None


@dataclass
class IntentStep:
    action: str
    text: str | None = None


@dataclass
class IntentPlan:
    summary: str
    steps: list[IntentStep]


class TaskPlanner:
    def plan(self, state: TaskState, note_text: str) -> PlannerDecision | None:
        raise NotImplementedError


class IntentParser:
    def parse(self, state: TaskState, text: str) -> IntentPlan | None:
        raise NotImplementedError


class NullTaskPlanner(TaskPlanner):
    def plan(self, state: TaskState, note_text: str) -> PlannerDecision | None:
        return None


class NullIntentParser(IntentParser):
    def parse(self, state: TaskState, text: str) -> IntentPlan | None:
        return None


class OpenAITaskPlanner(TaskPlanner):
    def __init__(self, api_key: str, model: str) -> None:
        from openai import OpenAI

        self.client = OpenAI(api_key=api_key)
        self.model = model

    def plan(self, state: TaskState, note_text: str) -> PlannerDecision | None:
        prompt = self._build_prompt(state, note_text)
        response = self.client.responses.create(
            model=self.model,
            instructions=(
                "你是一個謹慎的遠端開發任務規劃器。"
                "請把使用者最新的一條備註轉成下一個最合理的步驟。"
                "如果下一步具體且安全，優先給出單一 shell 命令。"
                "summary 與 title 必須使用繁體中文。"
                "除 command 外，不要輸出英文說明。"
                "只允許回傳嚴格 JSON，欄位只有：summary, command, title。"
            ),
            input=prompt,
        )

        text = response.output_text.strip()
        try:
            data = json.loads(text)
        except json.JSONDecodeError as exc:
            raise RuntimeError("規劃器回傳格式異常，暫時無法解析下一步。") from exc
        summary = str(data.get("summary", "")).strip() or "已完成規劃檢查。"
        command_value = data.get("command")
        title_value = data.get("title")

        command = str(command_value).strip() if isinstance(command_value, str) and command_value.strip() else None
        title = str(title_value).strip() if isinstance(title_value, str) and title_value.strip() else None
        return PlannerDecision(summary=summary, command=command, title=title)

    def _build_prompt(self, state: TaskState, note_text: str) -> str:
        recent_notes = [
            {
                "author": note.author,
                "text": note.text,
                "result_summary": note.result_summary,
            }
            for note in state.notes[-8:]
        ]
        payload = {
            "task_title": state.title,
            "task_summary": state.summary,
            "status": state.status.value,
            "workdir": state.workdir,
            "latest_update": state.latest_update,
            "last_command": state.last_command,
            "recent_notes": recent_notes,
            "latest_user_note": note_text,
        }
        return json.dumps(payload, ensure_ascii=False, indent=2)


class OpenAIIntentParser(IntentParser):
    def __init__(self, api_key: str, model: str) -> None:
        from openai import OpenAI

        self.client = OpenAI(api_key=api_key)
        self.model = model

    def parse(self, state: TaskState, text: str) -> IntentPlan | None:
        payload = {
            "task_title": state.title,
            "task_id": state.task_id,
            "status": state.status.value,
            "latest_update": state.latest_update,
            "pending_count": sum(1 for note in state.notes if note.processed_at is None),
            "user_text": text,
        }
        response = self.client.responses.create(
            model=self.model,
            instructions=(
                "You parse Chinese Telegram requests into a conservative multi-step plan. "
                "Only use these actions: status, tasks, queue, progress, history, tail, pending, "
                "approve, reject, pause, continue, create_task, switch_task, set_title, set_workdir, note. "
                "Do not invent shell commands. Do not use run_command. "
                "If unsure, return a single note step. "
                "Return strict JSON with keys: summary, steps. Each step has keys: action, text."
            ),
            input=json.dumps(payload, ensure_ascii=False, indent=2),
        )
        data = json.loads(response.output_text.strip())
        raw_steps = data.get("steps") or []
        steps: list[IntentStep] = []
        for step in raw_steps:
            action = str(step.get("action", "")).strip()
            text_value = step.get("text")
            text_item = str(text_value).strip() if isinstance(text_value, str) and text_value.strip() else None
            if action:
                steps.append(IntentStep(action=action, text=text_item))
        if not steps:
            return None
        summary = str(data.get("summary", "")).strip() or "已拆解请求。"
        return IntentPlan(summary=summary, steps=steps)
