# Copyright © The Debusine Developers
# See the AUTHORS file at the top-level directory of this distribution
#
# This file is part of Debusine. It is subject to the license terms
# in the LICENSE file found in the top-level directory of this
# distribution. No part of Debusine, including this file, may be copied,
# modified, propagated, or distributed except according to the terms
# contained in the LICENSE file.

"""Transaction helpers."""

from typing import Literal

import pgtransaction
from pgtransaction import config


class AtomicWithUncachedRetry(pgtransaction.Atomic):
    """
    Like :py:class:`pgtransaction.Atomic`, but without caching ``retry``.

    See https://github.com/AmbitionEng/django-pgtransaction/issues/25.
    """

    @property
    def retry(self) -> int:
        """
        Lazily load the configured retry value.

        We do this so that atomic decorators can be instantiated without an
        implicit dependency on Django settings being configured.
        """
        if self._retry is not None:  # pragma: no cover
            return self._retry
        retry = config.retry()  # type: ignore[no-untyped-call]
        assert isinstance(retry, int)
        return retry


# Unfortunately we have to copy the complicated type annotations from
# `pgtransaction.atomic` until
# https://github.com/AmbitionEng/django-pgtransaction/issues/25 is fixed.
# This is simplified by removing `using` and `deferrable`, which we don't
# need here.
def atomic(
    savepoint: bool = True,
    durable: bool = False,
    *,
    isolation_level: Literal[
        "READ COMMITTED", "REPEATABLE READ", "SERIALIZABLE"
    ]
    | None = None,
    retry: int | None = None,
    read_mode: Literal["READ WRITE", "READ ONLY"] | None = None,
) -> AtomicWithUncachedRetry:
    """Like :py:func:`pgtransaction.atomic`, but without caching ``retry``."""
    return AtomicWithUncachedRetry(
        using=None,
        savepoint=savepoint,
        durable=durable,
        isolation_level=isolation_level,
        retry=retry,
        read_mode=read_mode,
        deferrable=None,
    )
