"""
Background task service for scheduled operations using Tortoise ORM.
"""

import asyncio
from datetime import timedelta

from app.core.logging import get_logger
from app.services.queue_processor import QueueProcessor

logger = get_logger("background_tasks")


class BackgroundTaskService:
    """Service for managing scheduled background tasks."""

    def __init__(self):
        self.timeout_check_task: asyncio.Task | None = None
        self.is_running = False
        self.timeout_check_interval = timedelta(hours=1)
        # Queue polling task (runs lightweight processing pass periodically)
        self.queue_poll_task: asyncio.Task | None = None
        self.queue_poll_interval_seconds: int = (
            100
        )
        # S3 data availability check task
        self.s3_check_task: asyncio.Task | None = None
        self.s3_check_interval_seconds: int = (
            100  # Check every 100 seconds for new data in S3
        )

    async def start_timeout_monitoring(self) -> None:
        """Start the timeout monitoring background task."""
        if self.is_running:
            logger.info("Timeout monitoring is already running")
            return

        try:
            self.is_running = True
            self.timeout_check_task = asyncio.create_task(
                self._timeout_monitoring_loop()
            )
            # Also start queue polling loop
            self.queue_poll_task = asyncio.create_task(self._queue_polling_loop())
            # Start S3 data availability check loop
            self.s3_check_task = asyncio.create_task(self._s3_data_check_loop())
            logger.info("Timeout monitoring and background tasks started successfully")
        except Exception as e:
            logger.error(f"Failed to start timeout monitoring: {e}")
            self.is_running = False
            raise

    async def stop_timeout_monitoring(self) -> None:
        """Stop the timeout monitoring background task."""
        if not self.is_running:
            logger.info("Timeout monitoring is not running")
            return

        try:
            self.is_running = False
            if self.timeout_check_task:
                self.timeout_check_task.cancel()
                try:
                    await self.timeout_check_task
                except asyncio.CancelledError:
                    pass
                self.timeout_check_task = None
            # Stop queue polling loop
            if self.queue_poll_task:
                self.queue_poll_task.cancel()
                try:
                    await self.queue_poll_task
                except asyncio.CancelledError:
                    pass
                self.queue_poll_task = None
            # Stop S3 data check loop
            if self.s3_check_task:
                self.s3_check_task.cancel()
                try:
                    await self.s3_check_task
                except asyncio.CancelledError:
                    pass
                self.s3_check_task = None
            logger.info("Timeout monitoring and background tasks stopped successfully")
        except Exception as e:
            logger.error(f"Failed to stop timeout monitoring: {e}")
            raise

    async def _timeout_monitoring_loop(self) -> None:
        """Main loop for timeout monitoring."""
        logger.info("Timeout monitoring loop started")

        while self.is_running:
            try:
                # Run timeout check
                await self.run_manual_timeout_check()

                # Wait for next interval
                await asyncio.sleep(self.timeout_check_interval.total_seconds())

            except asyncio.CancelledError:
                logger.info("Timeout monitoring loop cancelled")
                break
            except Exception as e:
                logger.error(f"Error in timeout monitoring loop: {e}")
                await asyncio.sleep(30)  # Wait before retrying

        logger.info("Timeout monitoring loop ended")

    async def _queue_polling_loop(self) -> None:
        """Continuously poll for new ready jobs and process them immediately."""
        logger.info("Queue polling loop started with immediate processing")
        processor = QueueProcessor()
        while self.is_running:
            try:
                # One processing pass; it will be quick if there are no ready jobs
                # The new logic will immediately pick up new jobs if slots are available
                result = await processor.process_queue()
                logger.info(f"Queue processing result: {result}")
                await asyncio.sleep(self.queue_poll_interval_seconds)
            except asyncio.CancelledError:
                logger.info("Queue polling loop cancelled")
                break
            except Exception as e:
                logger.error(f"Error in queue polling loop: {e}")
                await asyncio.sleep(self.queue_poll_interval_seconds)
        logger.info("Queue polling loop ended")

    async def _s3_data_check_loop(self) -> None:
        """Continuously check for jobs with data_process=0 and mark as 1 if data exists in S3."""
        logger.info("S3 data availability check loop started")
        processor = QueueProcessor()
        while self.is_running:
            try:
                result = await processor.check_s3_data_availability()
                logger.info(f"S3 data check result: {result}")
                await asyncio.sleep(self.s3_check_interval_seconds)
            except asyncio.CancelledError:
                logger.info("S3 data check loop cancelled")
                break
            except Exception as e:
                logger.error(f"Error in S3 data check loop: {e}")
                await asyncio.sleep(self.s3_check_interval_seconds)
        logger.info("S3 data check loop ended")

    async def run_manual_timeout_check(self) -> None:
        """Run a manual timeout check using the QueueProcessor."""
        try:
            processor = QueueProcessor()
            result = await processor.check_timeout_jobs()
            logger.info(f"Timeout check completed: {result}")
        except Exception as e:
            logger.error(f"Error running manual timeout check: {e}")
            raise
