"""Background task scheduler - Phase 10.4"""

from collections.abc import Callable, Coroutine
from typing import Any

from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.base import BaseTrigger

from .manager import BackgroundTaskManager, get_background_task_manager


class BackgroundScheduler:
    """Background task scheduler using APScheduler.

    Integrates with BackgroundTaskManager for task tracking and execution.
    """

    def __init__(self, task_manager: BackgroundTaskManager | None = None):
        """Initialize the scheduler.

        Args:
            task_manager: Optional BackgroundTaskManager instance.
                         If not provided, uses the global singleton.
        """
        self._scheduler = AsyncIOScheduler()
        self._task_manager = task_manager or get_background_task_manager()
        self._job_tasks: dict[str, str] = {}  # Maps APScheduler job_id to task_id

    def add_job(
        self,
        func: Callable[..., Coroutine[Any, Any, Any]],
        trigger: BaseTrigger,
        args: tuple[Any, ...] | None = None,
        kwargs: dict[str, Any] | None = None,
        id: str | None = None,
        name: str | None = None,
        **apscheduler_kwargs: Any,
    ) -> str:
        """Add a job to the scheduler.

        Args:
            func: Async function to execute
            trigger: APScheduler trigger (date, interval, cron, etc.)
            args: Positional arguments for the function
            kwargs: Keyword arguments for the function
            id: Unique job ID (auto-generated if not provided)
            name: Job name for display purposes
            **apscheduler_kwargs: Additional APScheduler options

        Returns:
            The job ID
        """
        job_id = id or f"job_{len(self._job_tasks)}"
        task_name = name or f"scheduled_task_{job_id}"

        # Wrap the async function to integrate with BackgroundTaskManager
        async def wrapped_func() -> None:
            coro = func(*(args or ()), **(kwargs or {}))
            task_id = self._task_manager.submit_task(task_name, coro)
            self._job_tasks[job_id] = task_id

        self._scheduler.add_job(
            wrapped_func,
            trigger=trigger,
            id=job_id,
            name=task_name,
            **apscheduler_kwargs,
        )

        return job_id

    def remove_job(self, job_id: str) -> bool:
        """Remove a job from the scheduler.

        Args:
            job_id: The ID of the job to remove

        Returns:
            True if job was removed, False if job didn't exist
        """
        try:
            self._scheduler.remove_job(job_id)
            # Clean up task mapping if exists
            if job_id in self._job_tasks:
                task_id = self._job_tasks.pop(job_id)
                # Cancel the background task if still running
                self._task_manager.cancel_task(task_id)
            return True
        except Exception:
            return False

    def list_jobs(self) -> list[dict[str, Any]]:
        """List all scheduled jobs.

        Returns:
            List of job information dictionaries
        """
        jobs = self._scheduler.get_jobs()
        return [
            {
                "id": job.id,
                "name": job.name,
                "next_run_time": job.next_run_time,
                "trigger": str(job.trigger),
            }
            for job in jobs
        ]

    def start(self) -> None:
        """Start the scheduler."""
        if not self._scheduler.running:
            self._scheduler.start()

    def shutdown(self, wait: bool = True) -> None:
        """Shutdown the scheduler.

        Args:
            wait: Whether to wait for running jobs to complete
        """
        if self._scheduler.running:
            self._scheduler.shutdown(wait=wait)

    def pause(self) -> None:
        """Pause the scheduler."""
        self._scheduler.pause()

    def resume(self) -> None:
        """Resume the scheduler."""
        self._scheduler.resume()

    @property
    def task_manager(self) -> BackgroundTaskManager:
        """Get the underlying task manager."""
        return self._task_manager


# Global scheduler instance
_scheduler: BackgroundScheduler | None = None


def get_background_scheduler() -> BackgroundScheduler:
    """Get the global BackgroundScheduler instance."""
    global _scheduler
    if _scheduler is None:
        _scheduler = BackgroundScheduler()
    return _scheduler
