#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
后台任务管理器
统一管理系统中的所有 asyncio.create_task 创建的后台任务
防止内存泄漏和异常被静默吞噬
"""

import asyncio
import weakref
from typing import Set, Optional, Callable, Any
from utils.logger import get_logger

logger = get_logger("utils.background_task_manager")


class BackgroundTaskManager:
    """
    后台任务管理器

    功能:
    1. 统一管理所有后台任务
    2. 自动记录任务异常
    3. 支持批量取消任务
    4. 使用WeakSet自动清理已完成任务
    """

    def __init__(self):
        """初始化任务管理器"""
        # 使用普通set存储任务引用，通过done_callback清理
        self._tasks: Set[asyncio.Task] = set()
        self._task_counter = 0

    def create_task(
        self,
        coro,
        name: Optional[str] = None,
        context: Optional[str] = None
    ) -> asyncio.Task:
        """
        创建并管理后台任务

        Args:
            coro: 协程对象
            name: 任务名称（可选）
            context: 任务上下文信息（用于日志）

        Returns:
            asyncio.Task: 创建的任务对象
        """
        self._task_counter += 1

        # 如果没有提供名称，使用自动编号
        if name is None:
            name = f"background_task_{self._task_counter}"

        # 创建任务
        task = asyncio.create_task(coro, name=name)

        # 添加完成回调
        task.add_done_callback(lambda t: self._task_done_callback(t, context))

        # 添加到任务集合
        self._tasks.add(task)

        logger.debug(f"创建后台任务: {name}, 当前任务数: {len(self._tasks)}")

        return task

    def _task_done_callback(self, task: asyncio.Task, context: Optional[str] = None):
        """
        任务完成回调

        Args:
            task: 完成的任务
            context: 任务上下文信息
        """
        task_name = task.get_name()

        # 从任务集合中移除
        self._tasks.discard(task)

        try:
            # 尝试获取任务结果，如果有异常会抛出
            exception = task.exception()

            if exception:
                context_info = f" (context: {context})" if context else ""
                logger.error(
                    f"后台任务异常: {task_name}{context_info}, "
                    f"异常类型: {type(exception).__name__}, "
                    f"异常信息: {str(exception)}"
                )
            else:
                logger.debug(f"后台任务完成: {task_name}")

        except asyncio.CancelledError:
            logger.debug(f"后台任务被取消: {task_name}")
        except Exception as e:
            logger.error(f"获取任务结果失败: {task_name}, 错误: {str(e)}")

    async def cancel_all(self, timeout: float = 5.0) -> int:
        """
        取消所有运行中的任务

        Args:
            timeout: 等待任务取消的超时时间（秒）

        Returns:
            int: 被取消的任务数量
        """
        if not self._tasks:
            logger.debug("没有需要取消的后台任务")
            return 0

        # 获取所有未完成的任务
        tasks_to_cancel = [t for t in self._tasks if not t.done()]

        if not tasks_to_cancel:
            logger.debug("所有后台任务已完成")
            return 0

        logger.info(f"开始取消 {len(tasks_to_cancel)} 个后台任务")

        # 取消所有任务
        for task in tasks_to_cancel:
            task.cancel()

        # 等待所有任务完成（带超时）
        try:
            await asyncio.wait_for(
                asyncio.gather(*tasks_to_cancel, return_exceptions=True),
                timeout=timeout
            )
        except asyncio.TimeoutError:
            logger.warning(f"取消任务超时 ({timeout}秒)，部分任务可能仍在运行")

        cancelled_count = len(tasks_to_cancel)
        logger.info(f"已取消 {cancelled_count} 个后台任务")

        return cancelled_count

    def get_running_tasks_count(self) -> int:
        """
        获取运行中的任务数量

        Returns:
            int: 运行中的任务数量
        """
        return len([t for t in self._tasks if not t.done()])

    def get_total_tasks_count(self) -> int:
        """
        获取总任务数量（包括已完成的）

        Returns:
            int: 总任务数量
        """
        return len(self._tasks)

    def get_stats(self) -> dict:
        """
        获取任务统计信息

        Returns:
            dict: 统计信息
        """
        total = len(self._tasks)
        running = len([t for t in self._tasks if not t.done()])
        completed = total - running

        return {
            "total": total,
            "running": running,
            "completed": completed,
            "created_count": self._task_counter
        }

    async def cleanup_done_tasks(self):
        """
        清理已完成的任务（可选的定期清理方法）
        注意：通过 done_callback 已经自动清理，此方法作为备用
        """
        before_count = len(self._tasks)
        self._tasks = {t for t in self._tasks if not t.done()}
        after_count = len(self._tasks)

        cleaned = before_count - after_count
        if cleaned > 0:
            logger.debug(f"清理了 {cleaned} 个已完成的任务")

        return cleaned


# 全局单例
background_task_manager = BackgroundTaskManager()


# 便捷函数
def create_background_task(
    coro,
    name: Optional[str] = None,
    context: Optional[str] = None
) -> asyncio.Task:
    """
    创建后台任务的便捷函数

    Args:
        coro: 协程对象
        name: 任务名称
        context: 任务上下文

    Returns:
        asyncio.Task: 创建的任务
    """
    return background_task_manager.create_task(coro, name=name, context=context)


async def cancel_all_background_tasks(timeout: float = 5.0) -> int:
    """
    取消所有后台任务的便捷函数

    Args:
        timeout: 超时时间（秒）

    Returns:
        int: 被取消的任务数量
    """
    return await background_task_manager.cancel_all(timeout=timeout)


def get_background_tasks_stats() -> dict:
    """
    获取后台任务统计信息的便捷函数

    Returns:
        dict: 统计信息
    """
    return background_task_manager.get_stats()
