"""Worker thread pool for non-blocking I/O operations."""

import logging
from typing import Callable, Any, Optional
from PyQt6.QtCore import QObject, pyqtSignal, QThreadPool, QRunnable, pyqtSlot
from functools import wraps

logger = logging.getLogger(__name__)


class Worker(QRunnable):
    """Generic worker that executes a function in a thread."""
    
    class Signals(QObject):
        """Signals for worker thread communication."""
        finished = pyqtSignal()
        error = pyqtSignal(Exception)
        result = pyqtSignal(object)
    
    def __init__(self, func: Callable, *args, **kwargs):
        super().__init__()
        self.func = func
        self.args = args
        self.kwargs = kwargs
        self.signals = self.Signals()
    
    @pyqtSlot()
    def run(self):
        """Run the function and emit signals."""
        try:
            result = self.func(*self.args, **self.kwargs)
            self.signals.result.emit(result)
        except Exception as e:
            logger.error(f"Worker error in {self.func.__name__}: {e}", exc_info=True)
            self.signals.error.emit(e)
        finally:
            self.signals.finished.emit()


class WorkerPool:
    """Thread pool manager for background operations."""
    
    def __init__(self, max_threads: int = 4):
        self.pool = QThreadPool()
        self.pool.setMaxThreadCount(max_threads)
        self._active_workers = {}
    
    def run(
        self,
        func: Callable,
        *args,
        on_result: Optional[Callable[[Any], None]] = None,
        on_error: Optional[Callable[[Exception], None]] = None,
        on_finished: Optional[Callable[[], None]] = None,
        worker_id: Optional[str] = None,
        **kwargs
    ) -> str:
        """
        Run a function in the thread pool.
        
        Args:
            func: Function to run
            on_result: Callback for result (called with result)
            on_error: Callback for errors (called with exception)
            on_finished: Callback when done
            worker_id: Optional ID to track this worker
            *args, **kwargs: Arguments to pass to func
        
        Returns:
            Worker ID for reference
        """
        worker = Worker(func, *args, **kwargs)
        
        if on_result:
            worker.signals.result.connect(on_result)
        if on_error:
            worker.signals.error.connect(on_error)
        if on_finished:
            worker.signals.finished.connect(on_finished)
        
        # Generate worker ID if not provided
        if worker_id is None:
            worker_id = f"worker_{id(worker)}"
        
        self._active_workers[worker_id] = worker
        
        # Clean up when finished
        def cleanup():
            self._active_workers.pop(worker_id, None)
        
        worker.signals.finished.connect(cleanup)
        
        self.pool.start(worker)
        return worker_id
    
    def wait_for_done(self, timeout_ms: int = 5000) -> bool:
        """Wait for all workers to finish."""
        return self.pool.waitForDone(timeout_ms)
    
    def stop_all(self):
        """Stop all workers."""
        self.pool.clear()
        self._active_workers.clear()
    
    def active_count(self) -> int:
        """Get number of active workers."""
        return len(self._active_workers)


# Global worker pool instance
_global_pool: Optional[WorkerPool] = None


def get_worker_pool() -> WorkerPool:
    """Get or create global worker pool."""
    global _global_pool
    if _global_pool is None:
        _global_pool = WorkerPool(max_threads=4)
    return _global_pool


def run_async(
    func: Callable,
    *args,
    on_result: Optional[Callable[[Any], None]] = None,
    on_error: Optional[Callable[[Exception], None]] = None,
    on_finished: Optional[Callable[[], None]] = None,
    **kwargs
) -> str:
    """Convenience function to run async task using global pool."""
    return get_worker_pool().run(
        func,
        *args,
        on_result=on_result,
        on_error=on_error,
        on_finished=on_finished,
        **kwargs
    )
