from uuid import UUID
import logging
from app.core.module_framework.cqrs import ICommand, ICommandHandler
from app.core.module_framework.decorators import transactional, log_execution
from app.core.postgres.base_pkg.base_client import BasePostgresClient
from app.modules.financial.domain.entities import ProjectBudget
from app.modules.financial.infrastructure.repositories import ProjectBudgetRepository

logger = logging.getLogger(__name__)

class InitializeBudgetCommand(ICommand):
    """Lệnh khởi tạo ngân sách ban đầu cho dự án"""
    project_id: UUID
    project_code: str

class InitializeBudgetCommandHandler(ICommandHandler[InitializeBudgetCommand, UUID]):
    def __init__(self, postgres_client: BasePostgresClient):
        self._postgres_client = postgres_client

    @log_execution
    @transactional
    def handle(self, command: InitializeBudgetCommand) -> UUID:
        repo = ProjectBudgetRepository(self._conn)
        
        budget = ProjectBudget(
            project_id=command.project_id,
            project_code=command.project_code
        )
        
        repo.save(budget)
        logger.info(f"Đã tự động khởi tạo ngân sách cho dự án {command.project_code}")
        
        return budget.id

class RequestDisbursementCommand(ICommand):
    """[D6] Lệnh yêu cầu giải ngân từ nguồn ngân sách."""
    project_id: UUID
    amount: float
    description: str

class RequestDisbursementCommandHandler(ICommandHandler[RequestDisbursementCommand, None]):
    def __init__(self, postgres_client: BasePostgresClient):
        self._postgres_client = postgres_client

    @log_execution
    @transactional
    def handle(self, command: RequestDisbursementCommand) -> None:
        repo = ProjectBudgetRepository(self._conn)
        
        # Lock dòng DB để tránh race condition trên ngân sách
        with self._conn.cursor() as cur:
            cur.execute("""
                SELECT * FROM financial.project_budgets 
                WHERE project_id = %s FOR UPDATE
            """, (str(command.project_id),))
            row = cur.fetchone()
            if not row:
                raise ValueError(f"Dự án {command.project_id} chưa được cấp ngân sách.")
                
            budget = ProjectBudget(**row)
            
            try:
                budget.lock_funds(command.amount)
                repo.save(budget)
                logger.info(f"[Financial] Đã giải ngân {command.amount} cho dự án {command.project_id}")
            except ValueError as e:
                # [D6] Cứu vãn: Đánh dấu FROZEN_OVER_BUDGET
                if budget.status == "FROZEN_OVER_BUDGET":
                    cur.execute("""
                        UPDATE financial.project_budgets
                        SET status = 'FROZEN_OVER_BUDGET'
                        WHERE id = %s
                    """, (str(budget.id),))
                    logger.error(f"[Financial] CHẶN GIẢI NGÂN: {e}")
                raise e
