"""
调度服务 - APScheduler 管理定时采集任务
"""
import logging
import re
from datetime import datetime, timedelta
from typing import Dict, Optional

from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.interval import IntervalTrigger
from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.date import DateTrigger
from apscheduler.executors.pool import ThreadPoolExecutor
from sqlalchemy.orm import Session

from app.database import SessionLocal
from app.services.collector import fetch_symbol_data
from app.services.cache import save_market_data, update_task_status
from app.config import SCHEDULER_MAX_INSTANCES, MAX_WORKERS

logger = logging.getLogger(__name__)

scheduler = BackgroundScheduler(
    executors={"default": ThreadPoolExecutor(max_workers=MAX_WORKERS)},
    job_defaults={
        "max_instances": SCHEDULER_MAX_INSTANCES,
        "misfire_grace_time": 60,
    },
)


def job_handler(task_id: int):
    """
    定时任务的执行函数。
    每个任务独立创建 DB session，避免跨线程问题。
    """
    db: Session = SessionLocal()
    try:
        from app.services.cache import get_task

        task = get_task(db, task_id)
        if not task or not task.enabled:
            logger.warning(f"任务 {task_id} 不存在或已禁用，停止执行")
            return

        periods = task.periods.split(",") if task.periods else []
        logger.info(f"[定时任务] 开始采集 {task.symbol} (periods={periods})")

        result = fetch_symbol_data(
            symbol=task.symbol,
            data_type=task.data_type,
            periods=periods,
            max_workers=MAX_WORKERS,
        )

        if result.get("timeframes"):
            save_market_data(db, task.symbol, result)
            update_task_status(db, task_id, "success")
            logger.info(f"[定时任务] {task.symbol} 采集成功")
            
            # 如果是一次性任务，标记为已完成并从调度器移除
            if task.task_type == "once":
                task.is_finished = True
                task.enabled = False
                db.commit()
                remove_job(task_id)
                logger.info(f"[定时任务] {task.symbol} 一次性任务已完成")
        else:
            update_task_status(db, task_id, "failed")
            logger.error(f"[定时任务] {task.symbol} 采集失败: {result.get('error')}")

    except Exception as e:
        logger.error(f"[定时任务] 执行异常 task_id={task_id}: {e}")
        try:
            update_task_status(db, task_id, "failed")
        except Exception:
            pass
    finally:
        db.close()


def start_scheduler():
    """启动调度器"""
    if not scheduler.running:
        scheduler.start()
        logger.info("调度器已启动")


def stop_scheduler():
    """停止调度器"""
    if scheduler.running:
        scheduler.shutdown(wait=False)
        logger.info("调度器已停止")


def add_job(task_id: int, interval_seconds: int, task_type: str = "interval", run_time: Optional[str] = None) -> str:
    """
    添加定时任务到调度器。

    Args:
        task_id: 任务ID
        interval_seconds: 间隔秒数
        task_type: 任务类型 (interval, daily, once)
        run_time: 执行时间，格式 HH:MM (用于daily和once类型)

    Returns:
        job_id
    """
    job_id = f"task_{task_id}"

    # 如果已存在，先移除
    if scheduler.get_job(job_id):
        scheduler.remove_job(job_id)

    # 根据任务类型选择trigger
    try:
        if task_type == "daily" and run_time:
            # 每天定时执行 - 验证run_time格式
            if not re.match(r'^\d{2}:\d{2}$', run_time):
                raise ValueError(f"run_time格式错误: {run_time}, 应为 HH:MM")
            
            hour, minute = map(int, run_time.split(":"))
            if not (0 <= hour <= 23 and 0 <= minute <= 59):
                raise ValueError(f"run_time值无效: {run_time}, 小时应为0-23, 分钟应为0-59")
            
            trigger = CronTrigger(hour=hour, minute=minute, timezone="Asia/Shanghai")
            
        elif task_type == "once" and run_time:
            # 仅执行一次 - 验证run_time格式
            if not re.match(r'^\d{2}:\d{2}$', run_time):
                raise ValueError(f"run_time格式错误: {run_time}, 应为 HH:MM")
            
            hour, minute = map(int, run_time.split(":"))
            if not (0 <= hour <= 23 and 0 <= minute <= 59):
                raise ValueError(f"run_time值无效: {run_time}, 小时应为0-23, 分钟应为0-59")
            
            now = datetime.now()
            run_dt = now.replace(hour=hour, minute=minute, second=0, microsecond=0)
            if run_dt <= now:
                # 如果时间已过，设置为明天（使用timedelta避免月末日期计算错误）
                run_dt = run_dt + timedelta(days=1)
            trigger = DateTrigger(run_date=run_dt, timezone="Asia/Shanghai")
        else:
            # 默认：间隔执行
            trigger = IntervalTrigger(seconds=interval_seconds)
    except ValueError as e:
        logger.error(f"任务 {task_id} 时间配置错误: {e}, 使用默认间隔触发器")
        trigger = IntervalTrigger(seconds=interval_seconds)

    scheduler.add_job(
        func=job_handler,
        trigger=trigger,
        args=[task_id],
        id=job_id,
        name=f"auto_collect_{task_id}",
        replace_existing=True,
    )
    logger.info(f"已添加定时任务: job_id={job_id}, type={task_type}, trigger={trigger}")
    return job_id


def remove_job(task_id: int) -> bool:
    """移除定时任务"""
    job_id = f"task_{task_id}"
    job = scheduler.get_job(job_id)
    if job:
        scheduler.remove_job(job_id)
        logger.info(f"已移除定时任务: {job_id}")
        return True
    return False


def is_job_running(task_id: int) -> bool:
    """检查任务是否正在调度器中运行"""
    job_id = f"task_{task_id}"
    return scheduler.get_job(job_id) is not None


def get_all_jobs() -> Dict[str, dict]:
    """获取所有活跃任务信息"""
    jobs = scheduler.get_jobs()
    result = {}
    for job in jobs:
        nrt = getattr(job, 'next_run_time', None)
        result[job.id] = {
            "name": job.name,
            "next_run_time": nrt.isoformat() if nrt else None,
            "trigger": str(job.trigger),
        }
    return result
