import functools
import logging
import time
from typing import Callable, Any

logger = logging.getLogger(__name__)

def transactional(handler_method: Callable) -> Callable:
    """
    Decorator bọc Command Handler trong một Database Transaction.
    Yêu cầu class (Handler) chứa method này phải có thuộc tính `_postgres_client`.
    """
    @functools.wraps(handler_method)
    def wrapper(self, *args, **kwargs):
        if not hasattr(self, "_postgres_client"):
            raise RuntimeError("Handler phải có self._postgres_client để sử dụng @transactional")
            
        def operation(conn):
            # Lưu transaction connection vào self để Repository bên trong có thể tái sử dụng
            # Đây là cách implementation Unit Of Work đơn giản trên raw DB driver
            old_conn = getattr(self, "_conn", None)
            self._conn = conn
            try:
                return handler_method(self, *args, **kwargs)
            finally:
                self._conn = old_conn
                
        return self._postgres_client.run_in_transaction(operation)
        
    return wrapper

def log_execution(handler_method: Callable) -> Callable:
    """
    Decorator tự động log thông tin input, thời gian xử lý và kết quả của Command/Query.
    """
    @functools.wraps(handler_method)
    def wrapper(self, *args, **kwargs):
        handler_name = self.__class__.__name__
        logger.info(f"[{handler_name}] Bắt đầu thực thi. args: {args}")
        start_time = time.time()
        try:
            result = handler_method(self, *args, **kwargs)
            elapsed = time.time() - start_time
            logger.info(f"[{handler_name}] Hoàn thành sau {elapsed:.3f}s")
            return result
        except Exception as e:
            elapsed = time.time() - start_time
            logger.error(f"[{handler_name}] Lỗi sau {elapsed:.3f}s: {str(e)}", exc_info=True)
            raise
    return wrapper
