"""
AbuLang Threading Support - Multi-threading capabilities
"""

import threading
import queue
import time
from typing import Callable, Any, List, Dict, Optional
from concurrent.futures import ThreadPoolExecutor, Future


class AbuThread:
    """Wrapper for AbuLang thread"""
    
    def __init__(self, target: Callable, args: tuple = (), kwargs: dict = None):
        self.target = target
        self.args = args
        self.kwargs = kwargs or {}
        self.thread = None
        self.result = None
        self.exception = None
    
    def start(self):
        """Start thread"""
        self.thread = threading.Thread(target=self._run)
        self.thread.start()
    
    def _run(self):
        """Run target function"""
        try:
            self.result = self.target(*self.args, **self.kwargs)
        except Exception as e:
            self.exception = e
    
    def join(self, timeout: Optional[float] = None):
        """Wait for thread to complete"""
        if self.thread:
            self.thread.join(timeout)
    
    def is_alive(self) -> bool:
        """Check if thread is running"""
        return self.thread.is_alive() if self.thread else False
    
    def get_result(self) -> Any:
        """Get thread result"""
        self.join()
        if self.exception:
            raise self.exception
        return self.result


class ThreadPool:
    """Thread pool for managing multiple threads"""
    
    def __init__(self, max_workers: int = 4):
        self.executor = ThreadPoolExecutor(max_workers=max_workers)
        self.futures: Dict[str, Future] = {}
    
    def submit(self, name: str, func: Callable, *args, **kwargs) -> Future:
        """Submit task to pool"""
        future = self.executor.submit(func, *args, **kwargs)
        self.futures[name] = future
        return future
    
    def get_result(self, name: str, timeout: Optional[float] = None) -> Any:
        """Get result of submitted task"""
        if name in self.futures:
            return self.futures[name].result(timeout=timeout)
        raise ValueError(f"Task not found: {name}")
    
    def wait_all(self, timeout: Optional[float] = None) -> bool:
        """Wait for all tasks to complete"""
        try:
            for future in self.futures.values():
                future.result(timeout=timeout)
            return True
        except Exception:
            return False
    
    def shutdown(self, wait: bool = True):
        """Shutdown thread pool"""
        self.executor.shutdown(wait=wait)
    
    def get_stats(self) -> Dict:
        """Get thread pool statistics"""
        return {
            "total_tasks": len(self.futures),
            "completed": sum(1 for f in self.futures.values() if f.done()),
            "running": sum(1 for f in self.futures.values() if not f.done())
        }


class ThreadSafeQueue:
    """Thread-safe queue for inter-thread communication"""
    
    def __init__(self, maxsize: int = 0):
        self.queue = queue.Queue(maxsize=maxsize)
    
    def put(self, item: Any, block: bool = True, timeout: Optional[float] = None):
        """Put item in queue"""
        self.queue.put(item, block=block, timeout=timeout)
    
    def get(self, block: bool = True, timeout: Optional[float] = None) -> Any:
        """Get item from queue"""
        return self.queue.get(block=block, timeout=timeout)
    
    def empty(self) -> bool:
        """Check if queue is empty"""
        return self.queue.empty()
    
    def size(self) -> int:
        """Get queue size"""
        return self.queue.qsize()


class Lock:
    """Thread lock for synchronization"""
    
    def __init__(self):
        self._lock = threading.Lock()
    
    def acquire(self, blocking: bool = True, timeout: float = -1) -> bool:
        """Acquire lock"""
        return self._lock.acquire(blocking=blocking, timeout=timeout)
    
    def release(self):
        """Release lock"""
        self._lock.release()
    
    def __enter__(self):
        """Context manager entry"""
        self.acquire()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """Context manager exit"""
        self.release()


class ThreadManager:
    """Manages threading operations"""
    
    def __init__(self):
        self.threads: Dict[str, AbuThread] = {}
        self.thread_pool = ThreadPool()
        self.locks: Dict[str, Lock] = {}
    
    def create_thread(self, name: str, target: Callable, args: tuple = (), kwargs: dict = None) -> AbuThread:
        """Create new thread"""
        thread = AbuThread(target, args, kwargs)
        self.threads[name] = thread
        return thread
    
    def start_thread(self, name: str):
        """Start thread"""
        if name in self.threads:
            self.threads[name].start()
    
    def join_thread(self, name: str, timeout: Optional[float] = None):
        """Wait for thread"""
        if name in self.threads:
            self.threads[name].join(timeout)
    
    def get_thread_result(self, name: str) -> Any:
        """Get thread result"""
        if name in self.threads:
            return self.threads[name].get_result()
    
    def create_lock(self, name: str) -> Lock:
        """Create named lock"""
        lock = Lock()
        self.locks[name] = lock
        return lock
    
    def get_lock(self, name: str) -> Optional[Lock]:
        """Get named lock"""
        return self.locks.get(name)
    
    def get_stats(self) -> Dict:
        """Get threading statistics"""
        return {
            "threads": len(self.threads),
            "active_threads": sum(1 for t in self.threads.values() if t.is_alive()),
            "locks": len(self.locks),
            "thread_pool": self.thread_pool.get_stats()
        }


# Global thread manager
_thread_manager = ThreadManager()


def get_thread_manager() -> ThreadManager:
    """Get global thread manager"""
    return _thread_manager
