"""
定时任务服务
使用 APScheduler 管理定时任务
"""
import logging
from datetime import datetime, timedelta
from typing import Optional
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy import select, and_, func

from app.core.config import settings
from app.models.user import User
from app.models.user_course_progress import UserCourseProgress, ProgressStatus
from app.models.task import Task, TaskAssignment

logger = logging.getLogger(__name__)

# 全局调度器实例
scheduler: Optional[AsyncIOScheduler] = None


async def get_db_session() -> AsyncSession:
    """获取数据库会话"""
    engine = create_async_engine(settings.DATABASE_URL, echo=False)
    async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
    return async_session()


async def send_learning_reminders():
    """
    发送学习提醒
    
    检查所有用户的学习进度，对长时间未学习的用户发送提醒
    """
    logger.info("开始执行学习提醒任务")
    
    try:
        db = await get_db_session()
        
        from app.services.notification_service import NotificationService
        notification_service = NotificationService(db)
        
        # 查找超过3天未学习的用户
        three_days_ago = datetime.now() - timedelta(days=3)
        
        result = await db.execute(
            select(UserCourseProgress, User).join(
                User, UserCourseProgress.user_id == User.id
            ).where(
                and_(
                    UserCourseProgress.status == ProgressStatus.IN_PROGRESS.value,
                    UserCourseProgress.last_accessed_at < three_days_ago,
                )
            )
        )
        
        inactive_progress = result.all()
        
        for progress, user in inactive_progress:
            # 获取课程名称
            from app.models.course import Course
            course_result = await db.execute(
                select(Course.name).where(Course.id == progress.course_id)
            )
            course_name = course_result.scalar() or "未知课程"
            
            days_inactive = (datetime.now() - progress.last_accessed_at).days
            
            # 发送提醒
            await notification_service.send_learning_reminder(
                user_id=user.id,
                course_name=course_name,
                days_inactive=days_inactive,
            )
            
            logger.info(f"已发送学习提醒: user_id={user.id}, course={course_name}")
        
        await db.close()
        logger.info(f"学习提醒任务完成，发送了 {len(inactive_progress)} 条提醒")
        
    except Exception as e:
        logger.error(f"学习提醒任务失败: {str(e)}")


async def send_task_deadline_reminders():
    """
    发送任务截止提醒
    
    检查即将到期的任务，发送提醒给相关用户
    """
    logger.info("开始执行任务截止提醒")
    
    try:
        db = await get_db_session()
        
        from app.services.notification_service import NotificationService
        notification_service = NotificationService(db)
        
        # 查找3天内到期的未完成任务
        now = datetime.now()
        three_days_later = now + timedelta(days=3)
        
        result = await db.execute(
            select(Task, TaskAssignment, User).join(
                TaskAssignment, Task.id == TaskAssignment.task_id
            ).join(
                User, TaskAssignment.user_id == User.id
            ).where(
                and_(
                    Task.end_time.between(now, three_days_later),
                    TaskAssignment.status.in_(["not_started", "in_progress"]),
                )
            )
        )
        
        upcoming_tasks = result.all()
        
        for task, assignment, user in upcoming_tasks:
            await notification_service.send_task_deadline_reminder(
                user_id=user.id,
                task_name=task.name,
                deadline=task.end_time,
            )
            
            logger.info(f"已发送任务截止提醒: user_id={user.id}, task={task.name}")
        
        await db.close()
        logger.info(f"任务截止提醒完成，发送了 {len(upcoming_tasks)} 条提醒")
        
    except Exception as e:
        logger.error(f"任务截止提醒失败: {str(e)}")


async def send_weekly_reports():
    """
    发送周学习报告
    
    每周一发送上周的学习统计报告
    """
    logger.info("开始生成周学习报告")
    
    try:
        db = await get_db_session()
        
        from app.services.notification_service import NotificationService
        notification_service = NotificationService(db)
        
        # 获取所有活跃用户
        result = await db.execute(
            select(User).where(User.is_active == True)
        )
        users = result.scalars().all()
        
        # 计算上周时间范围
        today = datetime.now().date()
        last_week_start = today - timedelta(days=today.weekday() + 7)
        last_week_end = last_week_start + timedelta(days=6)
        
        for user in users:
            # 统计学习时长
            study_time_result = await db.execute(
                select(func.coalesce(func.sum(UserCourseProgress.total_study_time), 0)).where(
                    and_(
                        UserCourseProgress.user_id == user.id,
                        UserCourseProgress.last_accessed_at.between(
                            datetime.combine(last_week_start, datetime.min.time()),
                            datetime.combine(last_week_end, datetime.max.time()),
                        )
                    )
                )
            )
            study_time = study_time_result.scalar() or 0
            
            # 统计完成课程数
            completed_result = await db.execute(
                select(func.count(UserCourseProgress.id)).where(
                    and_(
                        UserCourseProgress.user_id == user.id,
                        UserCourseProgress.status == ProgressStatus.COMPLETED.value,
                        UserCourseProgress.completed_at.between(
                            datetime.combine(last_week_start, datetime.min.time()),
                            datetime.combine(last_week_end, datetime.max.time()),
                        )
                    )
                )
            )
            courses_completed = completed_result.scalar() or 0
            
            # 如果有学习活动，发送报告
            if study_time > 0 or courses_completed > 0:
                await notification_service.send_weekly_report(
                    user_id=user.id,
                    study_time=study_time,
                    courses_completed=courses_completed,
                    exams_passed=0,  # TODO: 统计考试通过数
                )
                
                logger.info(f"已发送周报: user_id={user.id}")
        
        await db.close()
        logger.info("周学习报告发送完成")
        
    except Exception as e:
        logger.error(f"周学习报告发送失败: {str(e)}")


def init_scheduler():
    """初始化定时任务调度器"""
    global scheduler
    
    if scheduler is not None:
        return scheduler
    
    scheduler = AsyncIOScheduler()
    
    # 学习提醒：每天上午9点执行
    scheduler.add_job(
        send_learning_reminders,
        CronTrigger(hour=9, minute=0),
        id="learning_reminders",
        name="学习提醒",
        replace_existing=True,
    )
    
    # 任务截止提醒：每天上午10点执行
    scheduler.add_job(
        send_task_deadline_reminders,
        CronTrigger(hour=10, minute=0),
        id="task_deadline_reminders",
        name="任务截止提醒",
        replace_existing=True,
    )
    
    # 周学习报告：每周一上午8点发送
    scheduler.add_job(
        send_weekly_reports,
        CronTrigger(day_of_week="mon", hour=8, minute=0),
        id="weekly_reports",
        name="周学习报告",
        replace_existing=True,
    )
    
    logger.info("定时任务调度器初始化完成")
    return scheduler


def start_scheduler():
    """启动调度器"""
    global scheduler
    
    if scheduler is None:
        scheduler = init_scheduler()
    
    if not scheduler.running:
        scheduler.start()
        logger.info("定时任务调度器已启动")


def stop_scheduler():
    """停止调度器"""
    if scheduler and scheduler.running:
        scheduler.shutdown()
        logger.info("定时任务调度器已停止")


def get_scheduler() -> Optional[AsyncIOScheduler]:
    """获取调度器实例"""
    return scheduler
