"""Auto-generated stub for module: nvdec_worker_manager."""
from typing import Any, Dict, List, Optional, Set

from matrice_common.stream.cuda_shm_ring_buffer import GlobalFrameCounter
from matrice_common.stream.gpu_camera_map import GpuCameraMap
from nvdec import nvdec_pool_process, StreamConfig, DemuxerType, CUPY_AVAILABLE, PYNVCODEC_AVAILABLE, RING_BUFFER_AVAILABLE
import cupy as cp
import glob
import hashlib
import logging
import multiprocessing as mp
import os
import threading
import time

# Constants
logger: Any

# Functions
def get_available_gpu_count() -> int: ...
    """
    Detect the number of available CUDA GPUs.
    
        Returns:
            Number of available GPUs, or 1 if detection fails.
    """
def is_nvdec_available() -> bool: ...
    """
    Check if NVDEC backend is available.
    
        Requires:
            - CuPy with CUDA support
            - PyNvVideoCodec for NVDEC hardware decode
            - cuda_shm_ring_buffer module for CUDA IPC
    """

# Classes
class NVDECWorkerManager:
    """
    Manager for NVDEC worker processes - fully dynamic camera configuration.
    
        This manager wraps the existing nvdec_pool_process function to integrate
        with StreamingGateway. Key features:
    
        - Fully dynamic camera configuration (add, remove, update at runtime)
        - Smart per-GPU restarts: only restarts workers for GPUs whose cameras changed
        - Debounced batching: rapid successive changes are batched into a single restart
        - Stable GPU assignment: cameras are assigned to GPUs via consistent hashing,
          so add/remove of one camera doesn't shuffle other cameras across GPUs
        - Outputs to CUDA IPC ring buffers (not Redis/Kafka)
        - NV12 format output (50% smaller than RGB)
        - One worker process per GPU
    """

    def __init__(self: Any, camera_configs: List[Dict[str, Any]], stream_config: Dict[str, Any], gpu_id: int = 0, num_gpus: int = 0, nvdec_pool_size: int = 8, nvdec_burst_size: int = 4, frame_width: int = 640, frame_height: int = 640, num_slots: int = 32, target_fps: int = 0, duration_sec: float = 0, demuxer_type: str = 'nvc', restart_delay: float = 1.0) -> None: ...
        """
        Initialize NVDEC Worker Manager.
        
                Args:
                    camera_configs: List of camera configuration dicts with keys:
                        - camera_id or stream_key: Unique identifier (used for ring buffer naming)
                        - source: Video file path or RTSP URL
                        - width: Optional frame width (default: frame_width)
                        - height: Optional frame height (default: frame_height)
                        - fps: FPS limit for this camera (used by default)
                    stream_config: Stream configuration (unused, for interface consistency)
                    gpu_id: Primary GPU device ID (starting GPU for round-robin assignment)
                    num_gpus: Number of GPUs to use (0 = auto-detect all available GPUs)
                    nvdec_pool_size: Number of NVDEC decoders per GPU
                    nvdec_burst_size: Frames per stream before rotating to next
                    frame_width: Default output frame width (used if camera config doesn't specify)
                    frame_height: Default output frame height (used if camera config doesn't specify)
                    num_slots: Ring buffer slots per camera
                    target_fps: Global FPS override (0 = use per-camera FPS from config)
                    duration_sec: Duration to run (0 = infinite until stop)
                    demuxer_type: Demuxer backend - "nvc" (PyNvVideoCodec, fastest for files) or
                                  "gstreamer" (provides ABSOLUTE RTP timestamps for RTSP streams)
                    restart_delay: Seconds to wait before restarting after a config change,
                                   allowing multiple rapid changes to be batched into one restart
        """

    def add_camera(self: Any, camera_config: Dict[str, Any]) -> bool: ...
        """
        Add a new camera at runtime.
        
                The config change is applied immediately. If the manager is running,
                a debounced per-GPU restart is scheduled so that rapid successive adds
                are batched into a single restart affecting only the relevant GPU(s).
        
                Args:
                    camera_config: Camera configuration dict
        
                Returns:
                    True if the camera was accepted (restart may be pending)
        """

    def get_camera_assignments(self: Any) -> Dict[str, int]: ...
        """
        Return mapping of camera_id to GPU ID.
        
                Returns:
                    Dict mapping camera_id -> gpu_id
        """

    def get_worker_statistics(self: Any) -> Dict[str, Any]: ...
        """
        Return statistics from workers.
        
                Returns:
                    Dict with worker count, camera count, FPS metrics, per-GPU stats, etc.
        """

    def is_running(self: Any) -> bool: ...
        """
        Check if the manager is currently running.
        """

    def remove_camera(self: Any, stream_key: str) -> bool: ...
        """
        Remove a camera at runtime.
        
                Args:
                    stream_key: Camera ID / stream key to remove
        
                Returns:
                    True if the camera was found and removed (restart may be pending)
        """

    def restart_workers(self: Any) -> None: ...
        """
        Full restart of all workers (stops everything, then starts fresh).
        
                This is the heavy-weight approach. Prefer add_camera/remove_camera/update_camera
                which use smart per-GPU restarts with debouncing.
        """

    def start(self: Any) -> None: ...
        """
        Start NVDEC worker processes (one per GPU).
        
                Initializes shared multiprocessing primitives and starts a worker
                process for each GPU that has cameras assigned. If no cameras are
                configured, primitives are still created so that later add_camera
                calls can schedule per-GPU starts without a full restart.
        """

    def stop(self: Any, timeout: float = 15.0) -> None: ...
        """
        Stop all worker processes and cancel any pending restart.
        
                Args:
                    timeout: Maximum time to wait for each worker to stop gracefully
        """

    def update_camera(self: Any, camera_config: Dict[str, Any]) -> bool: ...
        """
        Update a camera's configuration at runtime.
        
                Args:
                    camera_config: Updated camera configuration dict
        
                Returns:
                    True if the camera was found and updated (restart may be pending)
        """

