class ThreadSafeTokenizerWrapper:
    def __init__(self, tokenizer, lock):
        self._tokenizer = tokenizer
        self._lock = lock

        self._thread_safe_methods = {
            '__call__', 'encode', 'decode', 'tokenize', 
            'encode_plus', 'batch_encode_plus', 'batch_decode'
        }
    
    def __getattr__(self, name):
        attr = getattr(self._tokenizer, name)
        
        if name in self._thread_safe_methods and callable(attr):
            def wrapped_method(*args, **kwargs):
                with self._lock:
                    return attr(*args, **kwargs)
            return wrapped_method
        
        return attr

    def __call__(self, *args, **kwargs):
        with self._lock:
            return self._tokenizer(*args, **kwargs)
    
    def __setattr__(self, name, value):
        if name.startswith('_'):
            super().__setattr__(name, value)
        else:
            setattr(self._tokenizer, name, value)
    
    def __dir__(self):
        return dir(self._tokenizer)


class ThreadSafeVAEWrapper:
    def __init__(self, vae, lock):
        self._vae = vae
        self._lock = lock

    def __getattr__(self, name):
        attr = getattr(self._vae, name)
        # métodos que queremos proteger
        if name in {"decode", "encode", "forward"} and callable(attr):
            def wrapped(*args, **kwargs):
                with self._lock:
                    return attr(*args, **kwargs)
            return wrapped
        return attr

    def __setattr__(self, name, value):
        if name.startswith("_"):
            super().__setattr__(name, value)
        else:
            setattr(self._vae, name, value)

class ThreadSafeImageProcessorWrapper:
    def __init__(self, proc, lock):
        self._proc = proc
        self._lock = lock

    def __getattr__(self, name):
        attr = getattr(self._proc, name)
        if name in {"postprocess", "preprocess"} and callable(attr):
            def wrapped(*args, **kwargs):
                with self._lock:
                    return attr(*args, **kwargs)
            return wrapped
        return attr

    def __setattr__(self, name, value):
        if name.startswith("_"):
            super().__setattr__(name, value)
        else:
            setattr(self._proc, name, value)