"""DMS事务、行锁和并发扩展入口。"""

from __future__ import annotations

from collections.abc import Callable, Generator
from contextlib import contextmanager
from time import sleep
from typing import Any, TypeVar

from sqlalchemy import Select
from sqlalchemy.exc import OperationalError
from sqlalchemy.orm import Session

from dms.extensions import db

T = TypeVar("T")
MYSQL_RETRYABLE_ERROR_CODES = {1205, 1213}


@contextmanager
def transaction() -> Generator[Session, None, None]:
    """提供统一提交和异常回滚边界。"""
    session = db.session
    try:
        yield session
        session.commit()
    except Exception:
        session.rollback()
        raise


def for_update(statement: Select[Any]) -> Select[Any]:
    """为后续业务服务提供 ``SELECT ... FOR UPDATE`` 入口。"""
    return statement.with_for_update()


def execute_with_deadlock_retry(
    operation: Callable[[], T],
    *,
    max_attempts: int = 3,
    base_delay_seconds: float = 0.05,
) -> T:
    """仅重试MySQL锁等待超时和死锁，供后续业务事务显式调用。"""
    if max_attempts < 1:
        raise ValueError("max_attempts必须大于等于1")

    for attempt in range(1, max_attempts + 1):
        try:
            return operation()
        except OperationalError as exc:
            db.session.rollback()
            error_code = exc.orig.args[0] if getattr(exc.orig, "args", ()) else None
            if error_code not in MYSQL_RETRYABLE_ERROR_CODES or attempt == max_attempts:
                raise
            sleep(base_delay_seconds * attempt)

    raise RuntimeError("不可达的事务重试状态")
