"""
Utility helpers vendored from AA core.

We re-implement ``clean_setting`` rather than importing it from
``allianceauth.services.modules.discord.utils`` so the audit
module's import surface remains explicit and the AA-private
import count stays bounded.
"""

from typing import TypeVar, overload

from django.conf import settings

from ._log import get_logger

logger = get_logger(__name__)

T = TypeVar("T")


@overload
def clean_setting(
    name: str,
    default_value: None,
    min_value: int | None = ...,
    max_value: int | None = ...,
    *,
    required_type: type[T],
) -> T | None: ...


@overload
def clean_setting(
    name: str,
    default_value: T,
    min_value: int | None = ...,
    max_value: int | None = ...,
    required_type: type[T] | None = ...,
) -> T: ...


def clean_setting(
    name: str,
    default_value: object,
    min_value: int | None = None,
    max_value: int | None = None,
    required_type: type | None = None,
) -> object:
    """
    Read a Django setting, falling back to the default on bad values.

    Mirrors ``allianceauth.services.modules.discord.utils.clean_setting``
    so the audit module behaves consistently with the rest of AA when
    operators set audit-specific settings in the same ``local.py``.
    Differences from upstream: type hints use PEP 604 unions; the
    docstring is rewritten for clarity.
    """
    if default_value is None and not required_type:
        raise ValueError("You must specify a required_type for None defaults")

    if not required_type:
        required_type = type(default_value)

    if min_value is None and required_type is int:
        min_value = 0

    if not hasattr(settings, name):
        return default_value

    raw = getattr(settings, name)
    if not isinstance(raw, required_type):
        logger.warning(
            "Setting %s has wrong type (%s); using default: %r",
            name,
            type(raw).__name__,
            default_value,
        )
        return default_value
    if min_value is not None and isinstance(raw, int) and raw < min_value:
        logger.warning(
            "Setting %s=%r is below min_value=%r; using default: %r",
            name,
            raw,
            min_value,
            default_value,
        )
        return default_value
    if max_value is not None and isinstance(raw, int) and raw > max_value:
        logger.warning(
            "Setting %s=%r is above max_value=%r; using default: %r",
            name,
            raw,
            max_value,
            default_value,
        )
        return default_value
    return raw
