# 中文注释：
# 文件：echobot/agent/task_queue.py
# 说明：智能体核心逻辑，包括主循环、上下文、记忆与任务队列。

"""Task Queue Manager - 任务队列管理器

提供任务队列、状态查询和完成通知功能。
"""

import asyncio
import json
import time
from pathlib import Path
from typing import Optional
from dataclasses import dataclass, field, asdict
from datetime import datetime
from enum import Enum


class TaskStatus(Enum):
    """任务状态"""

    PENDING = "pending"
    PROCESSING = "processing"
    COMPLETED = "completed"
    FAILED = "failed"


@dataclass
class Task:
    """任务数据类"""

    id: str
    content: str
    channel: str
    chat_id: str
    status: TaskStatus = TaskStatus.PENDING
    created_at: float = field(default_factory=time.time)
    started_at: Optional[float] = None
    completed_at: Optional[float] = None
    result: Optional[str] = None
    error: Optional[str] = None
    position: int = 0

    def to_dict(self) -> dict:
        """转换为字典"""
        data = asdict(self)
        data["status"] = self.status.value
        data["created_at"] = datetime.fromtimestamp(self.created_at).isoformat()
        if self.started_at:
            data["started_at"] = datetime.fromtimestamp(self.started_at).isoformat()
        if self.completed_at:
            data["completed_at"] = datetime.fromtimestamp(self.completed_at).isoformat()
        return data


class TaskQueueManager:
    """
    任务队列管理器

    功能：
    - 任务排队（先来先处理）
    - 任务状态查询
    - 任务完成通知
    - 任务历史记录
    """

    def __init__(self, max_history: int = 100, notification_enabled: bool = True):
        """
        初始化任务队列管理器

        Args:
            max_history: 最大历史任务数量
            notification_enabled: 是否启用完成通知
        """
        self._queue: asyncio.Queue = asyncio.Queue()
        self._history: list[Task] = []
        self._max_history = max_history
        self._notification_enabled = notification_enabled

        # 当前任务
        self._current_task: Optional[Task] = None
        self._current_channel: Optional[str] = None
        self._current_chat_id: Optional[str] = None

        # 锁
        self._lock = asyncio.Lock()

        # 统计
        self._stats = {
            "total_added": 0,
            "total_completed": 0,
            "total_failed": 0,
        }

        # 通知回调
        self._notification_callback: Optional[callable] = None

    def set_notification_callback(self, callback: callable) -> None:
        """
        设置任务完成通知回调

        Args:
            callback: 回调函数，签名: callback(task: Task)
        """
        self._notification_callback = callback

    async def add_task(self, content: str, channel: str, chat_id: str) -> Task:
        """
        添加任务到队列

        Args:
            content: 任务内容
            channel: 消息渠道
            chat_id: 聊天ID

        Returns:
            Task: 创建的任务对象
        """
        task_id = f"task_{int(time.time() * 1000)}_{hash(content) % 1000:03d}"

        position = self._queue.qsize() + 1

        task = Task(
            id=task_id,
            content=content,
            channel=channel,
            chat_id=chat_id,
            status=TaskStatus.PENDING,
            position=position,
        )

        await self._queue.put(task)
        self._history.insert(0, task)

        # 清理旧历史
        if len(self._history) > self._max_history:
            self._history = self._history[: self._max_history]

        self._stats["total_added"] += 1

        logger.info(f"Task added: {task_id} (position: {position})")
        return task

    async def get_next_task(self, channel: str, chat_id: str) -> Optional[Task]:
        """
        获取下一个任务

        Args:
            channel: 当前处理任务的渠道
            chat_id: 当前处理任务的聊天ID

        Returns:
            Task: 下一个任务，如果没有则返回None
        """
        try:
            task = await asyncio.wait_for(self._queue.get(), timeout=1.0)

            # 更新任务状态
            task.status = TaskStatus.PROCESSING
            task.started_at = time.time()
            task.channel = channel
            task.chat_id = chat_id

            self._current_task = task
            self._current_channel = channel
            self._current_chat_id = chat_id

            logger.info(f"Task started: {task.id}")
            return task

        except asyncio.TimeoutError:
            return None

    async def complete_task(self, result: str) -> Optional[Task]:
        """
        完成当前任务

        Args:
            result: 任务结果

        Returns:
            Task: 完成的任务对象
        """
        if not self._current_task:
            return None

        task = self._current_task
        task.status = TaskStatus.COMPLETED
        task.completed_at = time.time()
        task.result = result

        # 发送通知
        if self._notification_enabled and self._notification_callback:
            try:
                self._notification_callback(task)
            except Exception as e:
                logger.error(f"Notification callback failed: {e}")

        self._stats["total_completed"] += 1

        # 更新历史
        self._history.insert(0, task)
        if len(self._history) > self._max_history:
            self._history = self._history[: self._max_history]

        # 清除当前任务
        self._current_task = None
        self._current_channel = None
        self._current_chat_id = None

        logger.info(f"Task completed: {task.id}")
        return task

    async def fail_task(self, error: str) -> Optional[Task]:
        """
        标记任务失败

        Args:
            error: 错误信息

        Returns:
            Task: 失败的任务对象
        """
        if not self._current_task:
            return None

        task = self._current_task
        task.status = TaskStatus.FAILED
        task.completed_at = time.time()
        task.error = error

        self._stats["total_failed"] += 1

        # 更新历史
        self._history.insert(0, task)
        if len(self._history) > self._max_history:
            self._history = self._history[: self._max_history]

        # 清除当前任务
        self._current_task = None
        self._current_channel = None
        self._current_chat_id = None

        logger.error(f"Task failed: {task.id} - {error}")
        return task

    async def get_status(self) -> dict:
        """
        获取当前任务状态

        Returns:
            dict: 状态信息
        """
        queue_size = self._queue.qsize()

        current = None
        if self._current_task:
            elapsed = time.time() - self._current_task.started_at
            current = {
                "id": self._current_task.id,
                "content_preview": self._current_task.content[:50] + "...",
                "elapsed_seconds": round(elapsed, 1),
                "status": self._current_task.status.value,
            }

        # 等待中的任务
        pending = []
        temp_queue = asyncio.Queue()
        while not self._queue.empty():
            try:
                task = self._queue.get_nowait()
                pending.append(
                    {
                        "id": task.id,
                        "content_preview": task.content[:30] + "...",
                        "position": task.position,
                        "created_at": datetime.fromtimestamp(task.created_at).isoformat(),
                    }
                )
                await temp_queue.put(task)
            except asyncio.QueueEmpty:
                break

        # 恢复队列
        while not temp_queue.empty():
            await self._queue.put(temp_queue.get())

        return {
            "current": current,
            "pending_count": queue_size,
            "pending": pending[:5],  # 只返回前5个
            "history_count": len(self._history),
            "stats": self._stats,
        }

    def get_task_by_id(self, task_id: str) -> Optional[Task]:
        """
        根据ID获取任务

        Args:
            task_id: 任务ID

        Returns:
            Task: 任务对象，不存在则返回None
        """
        for task in self._history:
            if task.id == task_id:
                return task
        return None

    def get_recent_tasks(self, limit: int = 10) -> list[dict]:
        """
        获取最近任务列表

        Args:
            limit: 返回数量上限

        Returns:
            list[dict]: 任务列表
        """
        return [task.to_dict() for task in self._history[:limit]]

    async def get_queue_position(self, channel: str, chat_id: str) -> int:
        """
        获取指定用户在队列中的位置

        Args:
            channel: 消息渠道
            chat_id: 聊天ID

        Returns:
            int: 队列中的位置（1-based），0表示不在队列中
        """
        temp_queue = asyncio.Queue()
        position = 0

        while not self._queue.empty():
            try:
                task = self._queue.get_nowait()
                position += 1

                if task.channel == channel and task.chat_id == chat_id:
                    # 放回队列
                    while not temp_queue.empty():
                        self._queue.put(temp_queue.get())
                    self._queue.put(task)
                    return position

                await temp_queue.put(task)
            except asyncio.QueueEmpty:
                break

        # 恢复队列
        while not temp_queue.empty():
            await self._queue.put(temp_queue.get())

        return 0

    @property
    def is_processing(self) -> bool:
        """检查是否正在处理任务"""
        return self._current_task is not None

    @property
    def current_task_info(self) -> Optional[dict]:
        """获取当前任务信息"""
        if not self._current_task:
            return None

        elapsed = time.time() - self._current_task.started_at
        return {
            "task": self._current_task.content[:30] + "...",
            "elapsed_seconds": round(elapsed, 1),
            "task_id": self._current_task.id,
        }


# 导入 logger
from loguru import logger
