"""
Simple API for the queue system.

This module provides a high-level, user-friendly interface for managing
jobs with minimal user intervention.

Author: Vasiliy Zdanovskiy
email: vasilyvz@gmail.com
"""

import atexit
import signal
import sys
from typing import Dict, Any, Optional, Type, List
from contextlib import contextmanager

from .process_manager import ProcessManager, ProcessManagerConfig
from .jobs.base import QueueJobBase
from .exceptions import ProcessControlError


class QueueSystem:
    """
    Simple API for the queue system.

    Provides a high-level interface that automatically manages the process
    manager and handles cleanup.
    """

    def __init__(
        self,
        registry_path: str = "queuemgr_registry.jsonl",
        shutdown_timeout: float = 30.0,
    ):
        """
        Initialize the queue system.

        Args:
            registry_path: Path to the registry file.
            shutdown_timeout: Timeout for graceful shutdown.
        """
        self.config = ProcessManagerConfig(
            registry_path=registry_path, shutdown_timeout=shutdown_timeout
        )
        self._manager: Optional[ProcessManager] = None
        self._is_initialized = False

    def start(self) -> None:
        """
        Start the queue system.

        Raises:
            ProcessControlError: If the system is already running or fails to start.
        """
        if self._is_initialized:
            raise ProcessControlError("Queue system is already running")

        self._manager = ProcessManager(self.config)
        self._manager.start()
        self._is_initialized = True

        # Register cleanup handlers
        atexit.register(self._cleanup)
        signal.signal(signal.SIGTERM, self._signal_handler)
        signal.signal(signal.SIGINT, self._signal_handler)

    def stop(self) -> None:
        """Stop the queue system and all running jobs."""
        if not self._is_initialized:
            return

        if self._manager:
            self._manager.stop()
            self._manager = None

        self._is_initialized = False

    def is_running(self) -> bool:
        """Check if the queue system is running."""
        return all(
            [
                self._is_initialized,
                self._manager is not None,
                self._manager.is_running(),
            ]
        )

    def add_job(
        self, job_class: Type[QueueJobBase], job_id: str, params: Dict[str, Any]
    ) -> None:
        """
        Add a job to the queue.

        Args:
            job_class: Job class to instantiate.
            job_id: Unique job identifier.
            params: Job parameters.

        Raises:
            ProcessControlError: If the system is not running or command fails.
        """
        self._ensure_running()
        self._manager.add_job(job_class, job_id, params)

    def start_job(self, job_id: str) -> None:
        """
        Start a job.

        Args:
            job_id: Job identifier.

        Raises:
            ProcessControlError: If the system is not running or command fails.
        """
        self._ensure_running()
        self._manager.start_job(job_id)

    def stop_job(self, job_id: str) -> None:
        """
        Stop a job.

        Args:
            job_id: Job identifier.

        Raises:
            ProcessControlError: If the system is not running or command fails.
        """
        self._ensure_running()
        self._manager.stop_job(job_id)

    def delete_job(self, job_id: str, force: bool = False) -> None:
        """
        Delete a job.

        Args:
            job_id: Job identifier.
            force: Force deletion even if job is running.

        Raises:
            ProcessControlError: If the system is not running or command fails.
        """
        self._ensure_running()
        self._manager.delete_job(job_id, force)

    def get_job_status(self, job_id: str) -> Dict[str, Any]:
        """
        Get job status.

        Args:
            job_id: Job identifier.

        Returns:
            Job status information.

        Raises:
            ProcessControlError: If the system is not running or command fails.
        """
        self._ensure_running()
        return self._manager.get_job_status(job_id)

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

        Returns:
            List of job information.

        Raises:
            ProcessControlError: If the system is not running or command fails.
        """
        self._ensure_running()
        return self._manager.list_jobs()

    def _ensure_running(self) -> None:
        """Ensure the system is running."""
        if not self.is_running():
            raise ProcessControlError("Queue system is not running")

    def _cleanup(self) -> None:
        """Cleanup handler for atexit."""
        self.stop()

    def _signal_handler(self, signum, frame) -> None:
        """Signal handler for graceful shutdown."""
        print(f"\nReceived signal {signum}, shutting down gracefully...")
        self.stop()
        sys.exit(0)


# Global queue system instance
_global_queue: Optional[QueueSystem] = None


def get_queue_system(
    registry_path: str = "queuemgr_registry.jsonl", shutdown_timeout: float = 30.0
) -> QueueSystem:
    """
    Get or create the global queue system instance.

    Args:
        registry_path: Path to the registry file.
        shutdown_timeout: Timeout for graceful shutdown.

    Returns:
        The global queue system instance.
    """
    global _global_queue

    if _global_queue is None:
        _global_queue = QueueSystem(registry_path, shutdown_timeout)

    return _global_queue


@contextmanager
def queue_system(
    registry_path: str = "queuemgr_registry.jsonl", shutdown_timeout: float = 30.0
):
    """
    Context manager for the queue system.

    Automatically starts and stops the queue system.

    Args:
        registry_path: Path to the registry file.
        shutdown_timeout: Timeout for graceful shutdown.

    Yields:
        QueueSystem: The queue system instance.
    """
    queue = QueueSystem(registry_path, shutdown_timeout)

    try:
        queue.start()
        yield queue
    finally:
        queue.stop()


# Convenience functions for the global queue system
def add_job(job_class: Type[QueueJobBase], job_id: str, params: Dict[str, Any]) -> None:
    """Add a job to the global queue system."""
    get_queue_system().add_job(job_class, job_id, params)


def start_job(job_id: str) -> None:
    """Start a job in the global queue system."""
    get_queue_system().start_job(job_id)


def stop_job(job_id: str) -> None:
    """Stop a job in the global queue system."""
    get_queue_system().stop_job(job_id)


def delete_job(job_id: str, force: bool = False) -> None:
    """Delete a job from the global queue system."""
    get_queue_system().delete_job(job_id, force)


def get_job_status(job_id: str) -> Dict[str, Any]:
    """Get job status from the global queue system."""
    return get_queue_system().get_job_status(job_id)


def list_jobs() -> List[Dict[str, Any]]:
    """List all jobs in the global queue system."""
    return get_queue_system().list_jobs()


def start_queue_system(
    registry_path: str = "queuemgr_registry.jsonl", shutdown_timeout: float = 30.0
) -> None:
    """Start the global queue system."""
    get_queue_system(registry_path, shutdown_timeout).start()


def stop_queue_system() -> None:
    """Stop the global queue system."""
    global _global_queue
    if _global_queue:
        _global_queue.stop()
        _global_queue = None
