from typing import Optional
from uuid import UUID
from datetime import datetime
from decimal import Decimal
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.core.module_framework.event_bus import event_bus
from app.modules.banking.domain.entities import BankTransaction
from app.modules.banking.infrastructure.repositories import BankTransactionRepository

logger = logging.getLogger(__name__)

class RecordTransactionCommand(ICommand):
    bank_account_no: str
    amount: Decimal
    transaction_date: datetime
    description: str

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

    @log_execution
    @transactional
    def handle(self, command: RecordTransactionCommand) -> UUID:
        repo = BankTransactionRepository(self._conn)
        
        txn = BankTransaction(
            bank_account_no=command.bank_account_no,
            amount=command.amount,
            transaction_date=command.transaction_date,
            description=command.description
        )
        
        repo.save(txn)
        return txn.id

class ReconcileTransactionCommand(ICommand):
    transaction_id: UUID
    invoice_id: UUID

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

    @log_execution
    @transactional
    def handle(self, command: ReconcileTransactionCommand) -> None:
        repo = BankTransactionRepository(self._conn)
        
        # 1. Fetch transaction
        txn = repo.get_by_id(command.transaction_id)
        if not txn:
            raise ValueError(f"Không tìm thấy giao dịch {command.transaction_id}")
            
        with self._conn.cursor() as cur:
            cur.execute("""
                UPDATE banking.transactions
                SET reconciled = TRUE, reconciled_invoice_id = %s
                WHERE id = %s
            """, (str(command.invoice_id), str(command.transaction_id)))
            
        logger.info(f"[Banking] Giao dịch {command.transaction_id} đã được đối soát với hóa đơn {command.invoice_id}")
        
        event_payload = {
            "transaction_id": str(command.transaction_id),
            "invoice_id": str(command.invoice_id),
            "timestamp": datetime.utcnow().isoformat()
        }
        with self._conn.cursor() as cur:
            event_bus.publish_outbox(cur, "InvoiceReconciledIntegrationEvent", event_payload)

class UnmatchTransactionCommand(ICommand):
    """[D6] Lệnh gỡ đối soát khi Hóa đơn bị hủy."""
    invoice_id: UUID

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

    @log_execution
    @transactional
    def handle(self, command: UnmatchTransactionCommand) -> None:
        logger.info(f"[Banking] Đang gỡ đối soát cho các giao dịch liên quan đến hóa đơn {command.invoice_id}")
        with self._conn.cursor() as cur:
            cur.execute("""
                UPDATE banking.transactions
                SET reconciled = FALSE, reconciled_invoice_id = NULL
                WHERE reconciled_invoice_id = %s
            """, (str(command.invoice_id),))
            logger.info(f"[Banking] Đã revert {cur.rowcount} giao dịch về UNMATCHED.")

            
        logger.info(f"[Banking] Đã ghi nhận đối soát thành công giao dịch {txn.id}")
