"""
Settings module for vq-django-auth.

This module handles configuration settings for the vq-django-auth package.
Settings can be customized by adding a VQ_REST_AUTH dictionary in your Django settings.

Example:
    from vq_django_auth.choices import AUTH_METHOD_ENUM

    VQ_REST_AUTH = {
        'LOGIN_SERIALIZER': 'myapp.serializers.CustomLoginSerializer',
        'AUTH_METHOD': AuthMethod.TOKEN,
    }
"""

import importlib
from typing import (
    TYPE_CHECKING,
    Any,
    Dict,
)

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import gettext_lazy as _
from rest_framework.serializers import Serializer
from rest_framework.settings import APISettings

from vq_django_auth.utils import format_lazy

if TYPE_CHECKING:
    from rest_framework.settings import DefaultsSettings

    class VQDefaultsSettings(DefaultsSettings, total=False):
        LOGIN_SERIALIZER: str
        TOKEN_SERIALIZER: str
        USER_DETAILS_SERIALIZER: str
        PASSWORD_RESET_CONFIRM_SERIALIZER: str
        PASSWORD_CHANGE_SERIALIZER: str
        REGISTER_SERIALIZER: str
        PASSWORD_RESET_SEND_MAIL: str
        FRONT_RESET_PASSWORD_PATH: str | None
        AUTH_METHOD: str | None
        REQUIRE_SECURE_TRANSPORT: bool
        VQ_AUTH_THROTTLE: str


USER_SETTINGS = getattr(settings, "VQ_REST_AUTH", None)


DEFAULTS: "VQDefaultsSettings" = {
    # Serializers
    "LOGIN_SERIALIZER": "vq_django_auth.serializers.LoginSerializer",
    "TOKEN_SERIALIZER": "vq_django_auth.serializers.TokenSerializer",
    "USER_DETAILS_SERIALIZER": "vq_django_auth.serializers.UserDetailsSerializer",
    "PASSWORD_RESET_CONFIRM_SERIALIZER": "vq_django_auth.serializers.PasswordResetConfirmSerializer",
    "PASSWORD_CHANGE_SERIALIZER": "vq_django_auth.serializers.PasswordChangeSerializer",
    "REGISTER_SERIALIZER": "vq_django_auth.registration.serializers.RegisterSerializer",
    "PASSWORD_RESET_SEND_MAIL": "vq_django_auth.usecases.send_password_reset_email",
    # Password reset options
    "FRONT_RESET_PASSWORD_PATH": None,
    # Password change options
    # Authentication options
    "AUTH_METHOD": None,
    # Security settings
    "REQUIRE_SECURE_TRANSPORT": False,  # When True, requires HTTPS for auth endpoints
    "VQ_AUTH_THROTTLE": "10/min",
}

# List of settings that may be in string import notation.
IMPORT_STRINGS = (
    "TOKEN_SERIALIZER",
    "USER_DETAILS_SERIALIZER",
    "LOGIN_SERIALIZER",
    "PASSWORD_RESET_CONFIRM_SERIALIZER",
    "PASSWORD_CHANGE_SERIALIZER",
    "PASSWORD_RESET_SEND_MAIL",
    "REGISTER_SERIALIZER",
)

# List of settings that have been removed
REMOVED_SETTINGS: list[str] = []

# Settings that must be boolean values
BOOLEAN_SETTINGS: list[str] = []


class VQAPISettings(APISettings):  # pragma: no cover
    """
    Custom API Settings class that provides validation and error checking.
    """

    def __check_user_settings(self, user_settings: Dict[str, Any]) -> Dict[str, Any]:
        """
        Validate user settings and return the validated settings.

        Args:
            user_settings: Dictionary of user-defined settings

        Returns:
            Validated settings dictionary

        Raises:
            RuntimeError: If a removed setting is found
            ImproperlyConfigured: If a setting has an invalid value type
        """

        SETTINGS_DOC = "https://github.com/yourusername/vq-django-auth#configuration"

        # Check for removed settings
        for setting in REMOVED_SETTINGS:
            if setting in user_settings:
                raise RuntimeError(
                    format_lazy(
                        _(
                            "The '{}' setting has been removed. Please refer to '{}' for available settings."
                        ),
                        setting,
                        SETTINGS_DOC,
                    )
                )

        # Validate boolean settings
        for setting in BOOLEAN_SETTINGS:
            if setting in user_settings and not isinstance(
                user_settings[setting], bool
            ):
                raise ImproperlyConfigured(
                    f"The '{setting}' setting must be a boolean value."
                )

        # Validate serializer settings
        for setting in [
            "LOGIN_SERIALIZER",
            "TOKEN_SERIALIZER",
            "USER_DETAILS_SERIALIZER",
            "PASSWORD_RESET_CONFIRM_SERIALIZER",
            "PASSWORD_CHANGE_SERIALIZER",
            "REGISTER_SERIALIZER",
        ]:
            if setting in user_settings:
                value = user_settings[setting]
                if isinstance(value, str):
                    try:
                        module_path, class_name = value.rsplit(".", 1)
                        module = importlib.import_module(module_path)
                        serializer_cls = getattr(module, class_name)
                        if not issubclass(serializer_cls, Serializer):
                            raise ImproperlyConfigured(
                                f"The '{setting}' setting must be a serializer class."
                            )
                    except (ImportError, AttributeError, ValueError):
                        raise ImproperlyConfigured(
                            f"The '{setting}' setting failed to import: {value}"
                        )

        return user_settings

    def reload(self) -> None:
        """
        Reload settings from Django settings.

        This is useful when Django settings have changed during runtime.
        """
        self._user_settings = getattr(settings, "VQ_REST_AUTH", {})
        self._cached_attrs: set[str] = set()


api_settings = VQAPISettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS)
