"""
Jingrow Local 调度器 - 最小化高效实现
基于现代 Python 最佳实践
"""

import asyncio
import logging
import requests
import json
from datetime import datetime
from typing import Dict, Any, Optional, List
from dataclasses import dataclass
from contextlib import asynccontextmanager

from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger

from jingrow.services.queue import init_queue, execute_local_scheduled_job
from jingrow.utils.jingrow_api import (
    get_record_list,
    get_jingrow_system_timezone,
    get_agent_detail,
    update_record,
)
from jingrow.utils.auth import get_jingrow_api_headers
from jingrow.ai.pagetype.local_ai_agent.local_ai_agent import create_agent_job

logger = logging.getLogger(__name__)


def list_records_with_system_auth(pagetype: str, filters: list = None, fields: list = None, limit: int = None):

    from jingrow.config import Config
    
    try:
        base_url = f"{Config.jingrow_server_url}/api/data/{pagetype}"
        params = {}
        if filters:
            params['filters'] = json.dumps(filters, ensure_ascii=False)
        if fields:
            params['fields'] = json.dumps(fields, ensure_ascii=False)
        if isinstance(limit, int) and limit > 0:
            params['limit'] = str(limit)
        
        # 使用系统级认证
        headers = get_jingrow_api_headers()
        if not headers:
            return {'success': False, 'error': 'JINGROW_API_KEY 或 JINGROW_API_SECRET 未配置'}
        
        response = requests.get(base_url, params=params, headers=headers, timeout=20)
        
        if response.status_code == 200:
            data = response.json()
            # 兼容不同返回格式
            if isinstance(data, dict) and 'data' in data:
                return {'success': True, 'data': data['data']}
            if isinstance(data, list):
                return {'success': True, 'data': data}
            return {'success': True, 'data': [data]}
        else:
            return {'success': False, 'error': f"HTTP {response.status_code}: {response.text}"}
    except Exception as e:
        return {'success': False, 'error': str(e)}


@dataclass
class JobConfig:
    """任务配置"""
    name: str
    cron: str
    payload: Dict[str, Any]
    enabled: bool = True


class Scheduler:
    """最小化高效调度器"""
    
    def __init__(self):
        self._scheduler = AsyncIOScheduler()
        self._jobs: Dict[str, JobConfig] = {}
        self._running = False
    
    async def start(self):
        """启动调度器"""
        if self._running:
            return
            
        init_queue()
        self._scheduler.start()
        await self._load_jobs()
        self._running = True
        await self.start_database_watcher()  # 启动数据库监听器
        logger.info(f"调度器已启动，加载了 {len(self._jobs)} 个任务（包含数据库监听器）")
    
    async def stop(self):
        """停止调度器"""
        if not self._running:
            return
            
        self._scheduler.shutdown()
        self._running = False
        logger.info("调度器已停止")
    
    async def _load_jobs(self):
        """加载任务"""
        # 清空现有任务
        self._scheduler.remove_all_jobs()
        self._jobs.clear()
        
        # 只加载 Local Scheduled Job（包含智能体自动创建的定时任务）
        await self._load_scheduled_jobs()
    
    async def _load_scheduled_jobs(self):
        """加载定时任务"""
        try:
            # 获取所有必要的字段
            fields = ['name', 'method', 'cron_format', 'frequency', 'stopped', 'server_script']
            result = get_record_list('Local Scheduled Job', fields=fields)
            if isinstance(result, dict):
                if result.get('success'):
                    jobs = result.get('data', [])
                else:
                    error_msg = result.get('error', '未知错误')
                    if 'AuthenticationError' in error_msg:
                        logger.info("认证失败，跳过定时任务加载（需要用户登录后手动加载）")
                    else:
                        logger.warning(f"获取定时任务失败: {error_msg}")
                    return
            else:
                jobs = result if isinstance(result, list) else []
            enabled_jobs = [job for job in jobs if not job.get('stopped', 0)]
            
            for job_data in enabled_jobs:
                cron = self._get_cron_expression(job_data)
                if cron:
                    # 只处理智能体定时任务
                    method = job_data.get('method', '')
                    if method.startswith('jingrow/agents/execute_scheduled_agent:'):
                        # 智能体定时任务
                        agent_id = method.split(':', 1)[1]
                        # 获取智能体的实际名称
                        agent_detail = get_agent_detail(agent_id)
                        agent_name = agent_detail.get('agent_name', agent_id) if agent_detail else agent_id
                        
                        config = JobConfig(
                            name=job_data['name'],
                            cron=cron,
                            payload={
                                'target_type': 'agent',
                                'agent_id': agent_id,
                                'agent_name': agent_name,
                                'route': 'jingrow/agents/execute_scheduled_agent',
                            }
                        )
                        await self._add_job(config)
                    
        except Exception as e:
            logger.error(f"加载定时任务失败: {e}")
    
    
    async def _add_job(self, config: JobConfig):
        """添加任务"""
        try:
            # 获取系统时区
            system_timezone = get_jingrow_system_timezone()
            trigger = CronTrigger.from_crontab(config.cron, timezone=system_timezone)
            self._scheduler.add_job(
                self._execute_job,
                trigger=trigger,
                id=config.name,
                kwargs={'config': config},
                coalesce=True,
                max_instances=1
            )
            self._jobs[config.name] = config
            logger.info(f"添加任务: {config.name} ({config.cron})")
            
        except Exception as e:
            logger.error(f"添加任务失败 {config.name}: {e}")
    
    async def _execute_job(self, config: JobConfig):
        """执行任务"""
        try:
            logger.info(f"执行任务: {config.name}")
            logger.info(f"任务配置: {config.payload}")
            
            # 更新定时任务的最后执行时间（在任务开始执行时）
            await self._update_last_execution(config.name)            
            
            job_id = create_agent_job(
                agent_id=config.payload.get('agent_id'),
                agent_name=config.payload.get('agent_name'),
                session_cookie=None,  # 系统级执行
                route=config.payload.get('route', 'jingrow/agents/execute'),
                method=config.payload.get('method')
            )
            
            logger.info(f"任务 {config.name} 已发送到队列，job_id: {job_id}")
        except Exception as e:
            logger.error(f"执行任务失败 {config.name}: {e}")
    
    async def _update_last_execution(self, scheduled_job_name: str):
        """更新定时任务的最后执行时间"""
        try:
            update_data = {
                "last_execution": datetime.now().isoformat()
            }
            
            result = update_record("Local Scheduled Job", scheduled_job_name, update_data)
            if result.get("success"):
                logger.info(f"Updated last_execution for scheduled job: {scheduled_job_name}")
            else:
                logger.error(f"Failed to update last_execution for scheduled job {scheduled_job_name}: {result.get('message')}")
                
        except Exception as e:
            logger.error(f"Failed to update last_execution for scheduled job {scheduled_job_name}: {e}")
    
    def _get_cron_expression(self, job_data: Dict[str, Any]) -> Optional[str]:
        """获取 cron 表达式"""
        cron_format = job_data.get('cron_format')
        if cron_format:
            return cron_format
            
        frequency = job_data.get('frequency', 'All')
        cron_map = {
            "Yearly": "0 0 1 1 *",
            "Monthly": "0 0 1 * *",
            "Weekly": "0 0 * * 0",
            "Daily": "0 0 * * *",
            "Hourly": "0 * * * *",
            "All": "*/4 * * * *",
        }
        return cron_map.get(frequency, "* * * * *")
    
    def get_status(self) -> Dict[str, Any]:
        """获取状态"""
        jobs = []
        for name, config in self._jobs.items():
            scheduler_job = self._scheduler.get_job(name)
            jobs.append({
                'name': name,
                'cron': config.cron,
                'enabled': scheduler_job is not None,
                'next_run': scheduler_job.next_run_time.isoformat() if scheduler_job and scheduler_job.next_run_time else None
            })
        
        return {
            'running': self._running,
            'total_jobs': len(jobs),
            'jobs': jobs
        }
    
    async def reload(self):
        """重新加载任务"""
        await self._load_jobs()
    
    async def start_database_watcher(self):
        """启动数据库监听器 - 监听 Local Scheduled Job 表的变化"""
        try:
            # 启动后台任务监听数据库变化
            asyncio.create_task(self._watch_database_changes())
            logger.info("数据库监听器已启动")
        except Exception as e:
            logger.error(f"启动数据库监听器失败: {e}")
    
    async def _watch_database_changes(self):
        """监听数据库变化"""
        last_check_time = None
        
        while self._running:
            try:
                # 获取最新的记录修改时间
                current_time = await self._get_latest_modification_time()
                
                # 如果有变化，重新加载任务
                if last_check_time is None or current_time != last_check_time:
                    await self._load_jobs()
                    last_check_time = current_time
                
                # 每5秒检查一次
                await asyncio.sleep(5)
                
            except Exception as e:
                logger.error(f"数据库监听异常: {e}")
                await asyncio.sleep(10)  # 出错时等待更长时间
    
    async def _get_latest_modification_time(self):
        """获取最新的记录修改时间"""
        try:
            # 只获取修改时间字段
            fields = ['modified']
            result = get_record_list('Local Scheduled Job', fields=fields)
            
            if isinstance(result, dict) and result.get('success'):
                jobs = result.get('data', [])
                if jobs:
                    # 获取最新的修改时间
                    latest_time = max(job.get('modified', '') for job in jobs)
                    return latest_time
            
            return None
            
        except Exception as e:
            logger.error(f"获取最新修改时间失败: {e}")
            return None

# 全局调度器实例
_scheduler: Optional[Scheduler] = None


def get_scheduler() -> Scheduler:
    """获取调度器实例"""
    global _scheduler
    if _scheduler is None:
        _scheduler = Scheduler()
    return _scheduler


async def start_scheduler():
    """启动调度器"""
    scheduler = get_scheduler()
    await scheduler.start()


async def stop_scheduler():
    """停止调度器"""
    scheduler = get_scheduler()
    await scheduler.stop()


def get_scheduler_status():
    """获取调度器状态"""
    scheduler = get_scheduler()
    return scheduler.get_status()
