from datetime import datetime
from typing import Optional
from uuid import UUID

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.core.module_framework.event_bus import event_bus

from app.modules.projects.domain.entities import Project
from app.modules.projects.infrastructure.repositories import ProjectRepository

class CreateProjectCommand(ICommand):
    """Data Transfer Object (DTO) mang ý định tạo Dự án mới"""
    name: str
    project_code: str
    start_date: datetime
    description: Optional[str] = None

class CreateProjectCommandHandler(ICommandHandler[CreateProjectCommand, UUID]):
    """
    Xử lý logic tạo Dự án. Áp dụng Transactional và Ghi Log tự động.
    """
    def __init__(self, postgres_client: BasePostgresClient):
        self._postgres_client = postgres_client

    @log_execution
    @transactional
    def handle(self, command: CreateProjectCommand) -> UUID:
        # self._conn được tự động inject bởi decorator @transactional
        repo = ProjectRepository(self._conn)
        
        # 1. Khởi tạo Domain Entity (Business Rules sẽ tự động chạy trong __init__ của Pydantic)
        project = Project(
            name=command.name,
            project_code=command.project_code,
            start_date=command.start_date,
            description=command.description
        )
        
        # 2. Persist Entity vào Cơ sở dữ liệu
        repo.save(project)
        
        # 3. Ghi Event vào Outbox để đảm bảo Transactional Consistency
        event_payload = {
            "project_id": str(project.id),
            "project_code": project.project_code,
            "name": project.name,
            "timestamp": datetime.utcnow().isoformat()
        }
        with self._conn.cursor() as cur:
            event_bus.publish_outbox(cur, "ProjectCreatedIntegrationEvent", event_payload)
            
        return project.id
