# thread_manager.py
from threading import Event, Thread, Lock
from ws_package.log.writer import LogWriter

logger = LogWriter.file(__name__)
thread_controls = {}
_controls_lock = Lock()

# Worker thread registry for fire-and-forget threads (reconnect, retry, report, etc.)
_worker_threads = {}  # name -> thread
_worker_lock = Lock()
_duplicate_attempts = 0  # Track duplicate worker start attempts

def register_thread(name: str, thread: Thread, stop_event: Event):
    with _controls_lock:
        thread_controls[name] = {"thread": thread, "stop_event": stop_event}

def stop_thread(name: str):
    logger.info("Stopping thread: %s", name)
    with _controls_lock:
        control = thread_controls.get(name)
    if control:
        stop_event = control["stop_event"]
        thread = control["thread"]
        if thread.is_alive():
            stop_event.set()
            thread.join(timeout=5)

def stop_all_threads():
    with _controls_lock:
        names = list(thread_controls.keys())
    for name in names:
        if name != "status":
            stop_thread(name)

def is_thread_alive(name: str):
    with _controls_lock:
        control = thread_controls.get(name)
    return control and control["thread"].is_alive()

# ==================== WORKER THREAD REGISTRY ====================
# For tracking fire-and-forget threads (reconnect, retry, report, etc.)

def register_worker(name: str, thread: Thread) -> bool:
    """
    Register a worker thread with cleanup tracking.
    Stops existing worker with same name if running to prevent duplicates.
    
    Args:
        name: Unique name for the worker thread
        thread: Thread object to register
    
    Returns:
        True if registered successfully, False if duplicate was prevented
    """
    global _duplicate_attempts
    
    with _worker_lock:
        # Stop existing worker if running
        if name in _worker_threads:
            old_thread = _worker_threads[name]
            if old_thread.is_alive():
                _duplicate_attempts += 1
                logger.warning("Duplicate worker start attempt: '%s' (total duplicates: %s)", name, _duplicate_attempts)
                logger.debug("Stopping existing worker thread '%s' before registering new one", name)
                try:
                    old_thread.join(timeout=2)
                    if old_thread.is_alive():
                        logger.warning("Worker thread '%s' did not stop within timeout, continuing anyway", name)
                except Exception as e:
                    logger.debug("Error stopping existing worker thread '%s': %s", name, e)
        
        _worker_threads[name] = thread
        logger.debug("Registered worker thread '%s'", name)
        return True

def stop_worker(name: str):
    """
    Stop a specific worker thread by name.
    
    Args:
        name: Name of the worker thread to stop
    """
    with _worker_lock:
        if name in _worker_threads:
            thread = _worker_threads[name]
            if thread.is_alive():
                logger.debug("Stopping worker thread '%s'", name)
                try:
                    thread.join(timeout=2)
                    if thread.is_alive():
                        logger.warning("Worker thread '%s' did not stop within timeout", name)
                except Exception as e:
                    logger.debug("Error stopping worker thread '%s': %s", name, e)
            del _worker_threads[name]

def is_worker_alive(name: str) -> bool:
    """
    Check if a worker thread is currently alive.
    
    Args:
        name: Name of the worker thread to check
        
    Returns:
        True if worker exists and is alive, False otherwise
    """
    with _worker_lock:
        if name in _worker_threads:
            return _worker_threads[name].is_alive()
        return False

def get_worker_count() -> int:
    """Get the number of registered worker threads."""
    with _worker_lock:
        return len(_worker_threads)

