# [DEF:TransactionCore:Module]
# @TIER: CRITICAL
# @SEMANTICS: Finance, ACID, Transfer, Ledger
# @PURPOSE: Core banking transaction processor with ACID guarantees.
# @LAYER: Domain (Core)
# @RELATION: DEPENDS_ON -> [DEF:Infra:PostgresDB]
#
# @INVARIANT: Total system balance must remain constant (Double-Entry Bookkeeping).
# @INVARIANT: Negative transfers are strictly forbidden.

# --- Test Specifications ---
# @TEST_CONTRACT: TransferRequestDTO -> TransferResultDTO
# @TEST_SCENARIO: sufficient_funds -> Returns COMPLETED, balances updated.
# @TEST_FIXTURE: sufficient_funds -> file:./__tests__/fixtures/transfers.json#happy_path
# @TEST_EDGE: insufficient_funds -> Throws BusinessRuleViolation("INSUFFICIENT_FUNDS").
# @TEST_EDGE: negative_amount -> Throws BusinessRuleViolation("Transfer amount must be positive.").
# @TEST_EDGE: concurrency_conflict -> Throws DBTransactionError.
#
# @TEST_INVARIANT: total_balance_constant -> VERIFIED_BY: [sufficient_funds, concurrency_conflict]
# @TEST_INVARIANT: negative_transfer_forbidden -> VERIFIED_BY: [negative_amount]

from decimal import Decimal
from typing import NamedTuple
# GRACE: Импорт глобального логгера с семантическими методами
from ...core.logger import logger, belief_scope 
from ...core.db import atomic_transaction, get_balance, update_balance
from ...core.audit import log_audit_trail
from ...core.exceptions import BusinessRuleViolation

class TransferResult(NamedTuple):
    tx_id: str
    status: str
    new_balance: Decimal

# [DEF:execute_transfer:Function]
# @PURPOSE: Atomically move funds between accounts with audit trails.
# @DATA_CONTRACT: Input -> (sender_id: str, receiver_id: str, amount: Decimal), Output -> TransferResult
# @PRE: amount > 0; sender != receiver; sender_balance >= amount.
# @POST: sender_balance -= amount; receiver_balance += amount; Audit Record Created.
# @SIDE_EFFECT: Database mutation (Rows locked), Audit IO.
#
# @UX_STATE: Success -> Returns 200 OK + Transaction Receipt.
# @UX_STATE: Error(LowBalance) -> 422 Unprocessable -> UI shows "Top-up needed" modal.
def execute_transfer(sender_id: str, receiver_id: str, amount: Decimal) -> TransferResult:
    # Guard: Input Validation (Вне belief_scope, так как это trivial проверка)
    if amount <= Decimal("0.00"):
        raise BusinessRuleViolation("Transfer amount must be positive.")
    if sender_id == receiver_id:
        raise BusinessRuleViolation("Cannot transfer to self.")

    # GRACE: Используем strict Context Manager без 'as context'
    with belief_scope("execute_transfer"):
        # GRACE: [REASON] - Жесткая дедукция, начало алгоритма
        logger.reason("Initiating transfer", extra={"from": sender_id, "to": receiver_id, "amount": amount})

        try:
            # @RELATION: CALLS -> atomic_transaction
            with atomic_transaction():
                current_balance = get_balance(sender_id, for_update=True)
                
                if current_balance < amount:
                    # GRACE: [EXPLORE] - Отклонение от Happy Path (фолбэк/ошибка)
                    logger.explore("Insufficient funds validation hit", extra={"balance": current_balance})
                    raise BusinessRuleViolation("INSUFFICIENT_FUNDS")

                # Mutation
                new_src_bal = update_balance(sender_id, -amount)
                new_dst_bal = update_balance(receiver_id, +amount)

                # Audit
                tx_id = log_audit_trail("TRANSFER", sender_id, receiver_id, amount)
                
                # GRACE:[REFLECT] - Сверка с @POST перед возвратом
                logger.reflect("Transfer committed successfully", extra={"tx_id": tx_id, "new_balance": new_src_bal})
                
                return TransferResult(tx_id, "COMPLETED", new_src_bal)

        except BusinessRuleViolation as e:
            # Explicit re-raise for UI mapping
            raise e
        except Exception as e:
            # GRACE: [EXPLORE] - Неожиданный сбой
            logger.explore("Critical Transfer Failure", exc_info=e)
            raise RuntimeError("TRANSACTION_ABORTED") from e
#[/DEF:execute_transfer:Function]

# [/DEF:TransactionCore:Module]