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

"""
APScheduler 调度器封装

特性:
- 基于 AsyncIOScheduler
- 支持 Cron/Interval/Date 触发器
- 支持任务装饰器注册
- 支持运行时动态添加/删除任务
- 支持任务状态查询
"""

from typing import Optional, Callable, Any, Dict, List
from datetime import datetime

from loguru import logger

try:
    from apscheduler.schedulers.asyncio import AsyncIOScheduler
    from apscheduler.triggers.cron import CronTrigger
    from apscheduler.triggers.interval import IntervalTrigger
    from apscheduler.triggers.date import DateTrigger
    from apscheduler.job import Job
    APSCHEDULER_AVAILABLE = True
except ImportError:
    AsyncIOScheduler = None
    CronTrigger = None
    IntervalTrigger = None
    DateTrigger = None
    Job = None
    APSCHEDULER_AVAILABLE = False


class SchedulerRegistry:

    def __init__(self):
        self.jobs: List[Dict[str, Any]] = []

    def register_job(
        self,
        func: Callable,
        trigger: str,
        trigger_args: Dict[str, Any],
        job_id: Optional[str] = None,
        name: Optional[str] = None,
        **kwargs
    ):
        job_info = {
            'func': func,
            'trigger': trigger,
            'trigger_args': trigger_args,
            'job_id': job_id or func.__name__,
            'name': name or func.__name__,
            'kwargs': kwargs,
        }
        self.jobs.append(job_info)
        logger.debug(f"📝 任务已注册: {job_info['job_id']}")

    def get_jobs(self) -> List[Dict[str, Any]]:
        return self.jobs

    def clear(self):
        self.jobs.clear()


class TaskScheduler:

    def __init__(self, timezone: str = 'Asia/Shanghai'):
        if not APSCHEDULER_AVAILABLE:
            raise ImportError(
                "APScheduler 未安装。请运行: pip install infomankit[scheduler]"
            )

        self.scheduler = AsyncIOScheduler(timezone=timezone)
        self.timezone = timezone
        self.registry = SchedulerRegistry()
        self._initialized = False

    def start(self):
        """启动调度器"""
        if not self.scheduler.running:
            # 添加注册表中的所有任务
            self._load_registered_jobs()

            # 启动调度器
            self.scheduler.start()
            self._initialized = True

            # 日志输出
            jobs = self.scheduler.get_jobs()
            logger.success(f"✅ 定时任务调度器已启动 (时区: {self.timezone})")

            if jobs:
                logger.info(f"📋 已注册 {len(jobs)} 个定时任务:")
                for job in jobs:
                    next_run = job.next_run_time.strftime('%Y-%m-%d %H:%M:%S') if job.next_run_time else 'N/A'
                    logger.info(f"   • {job.id}: {job.name} (下次运行: {next_run})")
            else:
                logger.warning("⚠️ 未注册任何定时任务")

    def shutdown(self, wait: bool = False):
        if self.scheduler.running:
            self.scheduler.shutdown(wait=wait)
            logger.info("⏹️ 定时任务调度器已关闭")

    def _load_registered_jobs(self):
        for job_info in self.registry.get_jobs():
            try:
                self.scheduler.add_job(
                    func=job_info['func'],
                    trigger=job_info['trigger'],
                    id=job_info['job_id'],
                    name=job_info['name'],
                    **job_info['trigger_args'],
                    **job_info['kwargs'],
                )
                logger.debug(f"✅ 任务已加载: {job_info['job_id']}")
            except Exception as e:
                logger.error(f"❌ 加载任务失败 {job_info['job_id']}: {e}")

    def add_job(
        self,
        func: Callable,
        trigger: str,
        job_id: Optional[str] = None,
        name: Optional[str] = None,
        **trigger_args
    ) -> Optional[Job]:
        try:
            job = self.scheduler.add_job(
                func=func,
                trigger=trigger,
                id=job_id or func.__name__,
                name=name or func.__name__,
                **trigger_args,
            )
            logger.info(f"➕ 动态添加任务: {job.id}")
            return job
        except Exception as e:
            logger.error(f"❌ 添加任务失败: {e}")
            return None

    def remove_job(self, job_id: str) -> bool:
        try:
            self.scheduler.remove_job(job_id)
            logger.info(f"🗑️ 移除任务: {job_id}")
            return True
        except Exception as e:
            logger.error(f"❌ 移除任务失败 {job_id}: {e}")
            return False

    def pause_job(self, job_id: str) -> bool:
        """暂停任务"""
        try:
            self.scheduler.pause_job(job_id)
            logger.info(f"⏸️ 暂停任务: {job_id}")
            return True
        except Exception as e:
            logger.error(f"❌ 暂停任务失败 {job_id}: {e}")
            return False

    def resume_job(self, job_id: str) -> bool:
        """恢复任务"""
        try:
            self.scheduler.resume_job(job_id)
            logger.info(f"▶️ 恢复任务: {job_id}")
            return True
        except Exception as e:
            logger.error(f"❌ 恢复任务失败 {job_id}: {e}")
            return False

    def get_jobs(self) -> List[Job]:
        """获取所有任务"""
        return self.scheduler.get_jobs()

    def get_job(self, job_id: str) -> Optional[Job]:
        """获取指定任务"""
        return self.scheduler.get_job(job_id)

    @property
    def is_running(self) -> bool:
        """调度器是否运行中"""
        return self.scheduler.running


# 全局调度器实例
task_scheduler: Optional[TaskScheduler] = None


def get_scheduler() -> TaskScheduler:
    """获取全局调度器实例"""
    global task_scheduler
    if task_scheduler is None:
        task_scheduler = TaskScheduler()
    return task_scheduler


# ========== 装饰器 ==========

def scheduled_task(
    trigger: str = 'cron',
    job_id: Optional[str] = None,
    name: Optional[str] = None,
    **trigger_args
):
    """
    定时任务装饰器

    Args:
        trigger: 触发器类型 ('cron', 'interval', 'date')
        job_id: 任务ID（唯一标识）
        name: 任务名称
        **trigger_args: 触发器参数

    Example (Cron):
        @scheduled_task(trigger='cron', hour=0, minute=0)
        async def daily_cleanup():
            # 每天 00:00 执行
            pass

    Example (Interval):
        @scheduled_task(trigger='interval', minutes=5)
        async def check_status():
            # 每 5 分钟执行
            pass

    Example (Date):
        @scheduled_task(trigger='date', run_date='2025-12-31 23:59:59')
        async def new_year_task():
            # 在指定时间执行一次
            pass
    """
    def decorator(func: Callable):
        scheduler = get_scheduler()
        scheduler.registry.register_job(
            func=func,
            trigger=trigger,
            trigger_args=trigger_args,
            job_id=job_id,
            name=name,
        )
        return func
    return decorator


def cron(
    job_id: Optional[str] = None,
    name: Optional[str] = None,
    **cron_args
):
    """
    Cron 定时任务装饰器（简化版）

    Args:
        job_id: 任务ID
        name: 任务名称
        **cron_args: Cron 参数 (year, month, day, week, day_of_week, hour, minute, second)

    Example:
        @cron(hour=0, minute=0)  # 每天 00:00
        async def daily_task():
            pass

        @cron(day_of_week='mon-fri', hour=9)  # 工作日早上 9 点
        async def workday_task():
            pass
    """
    return scheduled_task(trigger='cron', job_id=job_id, name=name, **cron_args)


def interval(
    job_id: Optional[str] = None,
    name: Optional[str] = None,
    **interval_args
):
    """
    间隔定时任务装饰器（简化版）

    Args:
        job_id: 任务ID
        name: 任务名称
        **interval_args: 间隔参数 (weeks, days, hours, minutes, seconds)

    Example:
        @interval(minutes=5)  # 每 5 分钟
        async def frequent_task():
            pass

        @interval(hours=1)  # 每小时
        async def hourly_task():
            pass
    """
    return scheduled_task(trigger='interval', job_id=job_id, name=name, **interval_args)
