import threading
from typing import Dict, List, TypeVar, Generic, Any, Type
from abc import ABC, abstractmethod

T = TypeVar('T')


class ThreadSafeBase(ABC, Generic[T]):
    
    def __init__(self):
        self._instances: Dict[int, Dict[str, T]] = {}
        self._lock = threading.Lock()
    
    @classmethod
    def _get_thread_instances(cls) -> Dict[str, T]:
        thread_id = threading.get_ident()
        
        if not hasattr(cls, '_global_instances'):
            cls._global_instances = {}
            cls._global_lock = threading.Lock()
        
        with cls._global_lock:
            if thread_id not in cls._global_instances:
                cls._global_instances[thread_id] = {}
            return cls._global_instances[thread_id]
    
    @classmethod
    def _get_polymorphic_instances(cls) -> Dict[str, T]:
        thread_id = threading.get_ident()
        
        if not hasattr(cls, '_polymorphic_instances'):
            cls._polymorphic_instances = {}
            cls._polymorphic_lock = threading.Lock()
        
        with cls._polymorphic_lock:
            if thread_id not in cls._polymorphic_instances:
                cls._polymorphic_instances[thread_id] = {}
            return cls._polymorphic_instances[thread_id]
    
    @classmethod
    def clear_thread_data(cls):
        thread_id = threading.get_ident()
        
        if not hasattr(cls, '_global_instances'):
            cls._global_instances = {}
            cls._global_lock = threading.Lock()
        
        if not hasattr(cls, '_polymorphic_instances'):
            cls._polymorphic_instances = {}
            cls._polymorphic_lock = threading.Lock()
        
        with cls._global_lock:
            cls._global_instances[thread_id] = {}
        
        with cls._polymorphic_lock:
            cls._polymorphic_instances[thread_id] = {}
    
    @classmethod
    def clear_all(cls):
        thread_id = threading.get_ident()
        
        if not hasattr(cls, '_global_instances'):
            cls._global_instances = {}
            cls._global_lock = threading.Lock()
        
        if not hasattr(cls, '_polymorphic_instances'):
            cls._polymorphic_instances = {}
            cls._polymorphic_lock = threading.Lock()
        
        with cls._global_lock:
            if thread_id in cls._global_instances:
                cls._global_instances[thread_id].clear()
        
        with cls._polymorphic_lock:
            if thread_id in cls._polymorphic_instances:
                cls._polymorphic_instances[thread_id].clear()
    
    @classmethod
    def get_all(cls) -> Dict[str, T]:
        return cls._get_thread_instances()
    
    @classmethod
    def get_all_polymorphic(cls) -> Dict[str, T]:
        return cls._get_polymorphic_instances()
    
    @classmethod
    def cleanup_thread(cls):
        if not hasattr(cls, '_global_instances'):
            return
        
        current_threads = {thread.ident for thread in threading.enumerate()}
        
        with cls._global_lock:
            dead_threads = [tid for tid in cls._global_instances.keys() if tid not in current_threads]
            for tid in dead_threads:
                del cls._global_instances[tid]
        
        if hasattr(cls, '_polymorphic_instances'):
            with cls._polymorphic_lock:
                dead_threads = [tid for tid in cls._polymorphic_instances.keys() if tid not in current_threads]
                for tid in dead_threads:
                    del cls._polymorphic_instances[tid]
    
    @abstractmethod
    def get_instance_key(self) -> str:
        pass
    
    def register_instance(self):
        instances = self._get_thread_instances()
        instances[self.get_instance_key()] = self
    
    def register_polymorphic_instance(self, base_class: Type[T]):
        if not hasattr(base_class, '_polymorphic_instances'):
            base_class._polymorphic_instances = {}
            base_class._polymorphic_lock = threading.Lock()
        
        thread_id = threading.get_ident()
        
        with base_class._polymorphic_lock:
            if thread_id not in base_class._polymorphic_instances:
                base_class._polymorphic_instances[thread_id] = {}
            base_class._polymorphic_instances[thread_id][self.get_instance_key()] = self


 