"""
Report Scheduler Service using APScheduler
==========================================

This module handles automated scheduling of weekly and monthly reports.
It uses APScheduler to run tasks at specific times without requiring Celery Beat.

Setup:
1. Install APScheduler: pip install apscheduler==3.10.4
2. Add this to your Django app's apps.py ready() method
3. Configure in settings.py

Usage:
    from apps.reporting.scheduler import start_report_scheduler
    start_report_scheduler()
"""

import logging
from datetime import datetime, time
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
from django.conf import settings
from django.utils import timezone
import pytz

logger = logging.getLogger(__name__)

# Global scheduler instance
_scheduler = None


def get_scheduler():
    """Get or create the scheduler instance"""
    global _scheduler
    if _scheduler is None:
        _scheduler = BackgroundScheduler(
            timezone=pytz.timezone(settings.TIME_ZONE),
            job_defaults={
                'coalesce': True,  # Combine multiple missed runs into one
                'max_instances': 1,  # Only one instance of each job at a time
                'misfire_grace_time': 3600  # Allow 1 hour grace for missed jobs
            }
        )
    return _scheduler


def send_weekly_reports_job():
    """
    Job function to send weekly reports
    Runs every Monday at 8:00 AM
    """
    from apps.reporting.tasks_sync import send_weekly_reports
    import threading
    
    logger.info("Starting weekly reports job")
    
    def run_task():
        try:
            result = send_weekly_reports()
            logger.info(f"Weekly reports completed: {result}")
        except Exception as e:
            logger.error(f"Error in weekly reports job: {str(e)}", exc_info=True)
    
    # Run in background thread to avoid blocking
    thread = threading.Thread(target=run_task)
    thread.daemon = True
    thread.start()
    
    logger.info("Weekly reports job started in background")


def send_monthly_reports_job():
    """
    Job function to send monthly reports
    Runs on the 1st day of each month at 6:00 AM
    """
    from apps.reporting.tasks_sync import generate_all_monthly_reports
    import threading
    
    logger.info("Starting monthly reports job")
    
    def run_task():
        try:
            result = generate_all_monthly_reports()
            logger.info(f"Monthly reports completed: {result}")
        except Exception as e:
            logger.error(f"Error in monthly reports job: {str(e)}", exc_info=True)
    
    thread = threading.Thread(target=run_task)
    thread.daemon = True
    thread.start()
    
    logger.info("Monthly reports job started in background")


def cleanup_old_reports_job():
    """
    Job function to cleanup old reports
    Runs daily at 2:00 AM
    """
    from apps.reporting.tasks_sync import cleanup_old_reports, cleanup_old_report_logs
    import threading
    
    logger.info("Starting cleanup job")
    
    def run_task():
        try:
            # Cleanup old report logs (90+ days)
            log_result = cleanup_old_report_logs()
            logger.info(f"Cleaned up old logs: {log_result}")
            
            # Cleanup old reports (90+ days)
            report_result = cleanup_old_reports()
            logger.info(f"Cleaned up old reports: {report_result}")
        except Exception as e:
            logger.error(f"Error in cleanup job: {str(e)}", exc_info=True)
    
    thread = threading.Thread(target=run_task)
    thread.daemon = True
    thread.start()
    
    logger.info("Cleanup job started in background")


def check_low_stock_job():
    """
    Job function to check low stock across all businesses
    Runs every Monday at 9:00 AM (after weekly reports)
    """
    from apps.reporting.tasks_sync import check_low_stock_all_businesses
    import threading
    
    logger.info("Starting low stock check job")
    
    def run_task():
        try:
            result = check_low_stock_all_businesses()
            logger.info(f"Low stock check completed: {result}")
        except Exception as e:
            logger.error(f"Error in low stock check job: {str(e)}", exc_info=True)
    
    thread = threading.Thread(target=run_task)
    thread.daemon = True
    thread.start()
    
    logger.info("Low stock check job started in background")


def check_warranty_expiry_job():
    """
    Job function to check warranty expiries
    Runs daily at 10:00 AM
    """
    from apps.reporting.tasks_sync import check_warranty_expiry_all_businesses
    import threading
    
    logger.info("Starting warranty expiry check job")
    
    def run_task():
        try:
            result = check_warranty_expiry_all_businesses()
            logger.info(f"Warranty expiry check completed: {result}")
        except Exception as e:
            logger.error(f"Error in warranty expiry check job: {str(e)}", exc_info=True)
    
    thread = threading.Thread(target=run_task)
    thread.daemon = True
    thread.start()
    
    logger.info("Warranty expiry check job started in background")


def start_report_scheduler():
    """
    Initialize and start the report scheduler
    
    Call this from your Django app's AppConfig.ready() method
    """
    scheduler = get_scheduler()
    
    # Prevent duplicate scheduling during Django reload
    if scheduler.running:
        logger.info("Scheduler already running, skipping initialization")
        return scheduler
    
    try:
        # Weekly Reports: Every Monday at 8:00 AM
        scheduler.add_job(
            send_weekly_reports_job,
            trigger=CronTrigger(
                day_of_week='mon',
                hour=8,
                minute=0,
                timezone=pytz.timezone(settings.TIME_ZONE)
            ),
            id='weekly_reports',
            name='Send Weekly Reports',
            replace_existing=True
        )
        logger.info("Scheduled: Weekly reports - Mondays at 8:00 AM")
        
        # Monthly Reports: 1st day of month at 6:00 AM
        scheduler.add_job(
            send_monthly_reports_job,
            trigger=CronTrigger(
                day=1,
                hour=6,
                minute=0,
                timezone=pytz.timezone(settings.TIME_ZONE)
            ),
            id='monthly_reports',
            name='Send Monthly Reports',
            replace_existing=True
        )
        logger.info("Scheduled: Monthly reports - 1st of month at 6:00 AM")
        
        # Low Stock Check: Every Monday at 9:00 AM
        scheduler.add_job(
            check_low_stock_job,
            trigger=CronTrigger(
                day_of_week='mon',
                hour=9,
                minute=0,
                timezone=pytz.timezone(settings.TIME_ZONE)
            ),
            id='low_stock_check',
            name='Check Low Stock',
            replace_existing=True
        )
        logger.info("Scheduled: Low stock check - Mondays at 9:00 AM")
        
        # Warranty Expiry Check: Daily at 10:00 AM
        scheduler.add_job(
            check_warranty_expiry_job,
            trigger=CronTrigger(
                hour=10,
                minute=0,
                timezone=pytz.timezone(settings.TIME_ZONE)
            ),
            id='warranty_expiry_check',
            name='Check Warranty Expiry',
            replace_existing=True
        )
        logger.info("Scheduled: Warranty expiry check - Daily at 10:00 AM")
        
        # Cleanup Old Reports: Daily at 2:00 AM
        scheduler.add_job(
            cleanup_old_reports_job,
            trigger=CronTrigger(
                hour=2,
                minute=0,
                timezone=pytz.timezone(settings.TIME_ZONE)
            ),
            id='cleanup_reports',
            name='Cleanup Old Reports',
            replace_existing=True
        )
        logger.info("Scheduled: Cleanup old reports - Daily at 2:00 AM")
        
        # Start the scheduler
        scheduler.start()
        logger.info("Report Scheduler started successfully!")
        
        # Print next run times
        logger.info("\nNext scheduled runs:")
        for job in scheduler.get_jobs():
            next_run = job.next_run_time
            logger.info(f"  - {job.name}: {next_run.strftime('%Y-%m-%d %H:%M:%S %Z')}")
        
        return scheduler
        
    except Exception as e:
        logger.error(f"Failed to start scheduler: {str(e)}", exc_info=True)
        raise


def stop_report_scheduler():
    """Stop the report scheduler"""
    global _scheduler
    if _scheduler and _scheduler.running:
        _scheduler.shutdown(wait=False)
        logger.info("Report Scheduler stopped")
        _scheduler = None


def get_scheduled_jobs():
    """Get list of all scheduled jobs with their next run times"""
    scheduler = get_scheduler()
    jobs = []
    
    for job in scheduler.get_jobs():
        jobs.append({
            'id': job.id,
            'name': job.name,
            'next_run': job.next_run_time.isoformat() if job.next_run_time else None,
            'trigger': str(job.trigger),
        })
    
    return jobs


def trigger_job_now(job_id: str):
    """
    Manually trigger a scheduled job immediately
    
    Args:
        job_id: ID of the job to trigger (e.g., 'weekly_reports', 'monthly_reports')
    
    Returns:
        bool: True if job was triggered successfully
    """
    scheduler = get_scheduler()
    
    try:
        job = scheduler.get_job(job_id)
        if job:
            job.modify(next_run_time=datetime.now())
            logger.info(f"Triggered job '{job_id}' to run immediately")
            return True
        else:
            logger.error(f"Job '{job_id}' not found")
            return False
    except Exception as e:
        logger.error(f"Error triggering job '{job_id}': {str(e)}")
        return False


# Convenience function for manual testing
def test_weekly_report(business_id=None):
    """
    Test weekly report generation for a specific business or all businesses
    
    Args:
        business_id: Optional business ID. If None, sends to all businesses.
    """
    from apps.reporting.tasks_sync import send_weekly_reports, send_business_weekly_report
    
    if business_id:
        logger.info(f"Testing weekly report for business {business_id}")
        result = send_business_weekly_report(business_id)
        logger.info(f"Test result: {result}")
    else:
        logger.info("Testing weekly reports for all businesses")
        result = send_weekly_reports()
        logger.info(f"Test result: {result}")
    
    return result