from dataclasses import dataclass
from functools import lru_cache

from django.conf import settings as django_settings


@dataclass
class JWTSettings:
    # Signing keys
    private_key: str  # Used for signing (required)
    public_key: str   # Used for verification (same as private for HS256)

    # Algorithm
    algorithm: str  # HS256, RS256, etc.

    # Token lifetimes (seconds)
    access_token_expires_in: int
    refresh_token_expires_in: int

    # Security options
    validate_session: bool  # Check session exists on token validation
    rotate_refresh_token: bool  # Issue new refresh token on refresh


@lru_cache
def get_settings() -> JWTSettings:
    private_key = getattr(django_settings, "JWT_PRIVATE_KEY", None)

    if private_key is None:
        raise ValueError(
            "JWT_PRIVATE_KEY must be set in Django settings. "
            "For HS256, use a secure random string. "
            "For RS256, use a PEM-encoded RSA private key."
        )

    algorithm = getattr(django_settings, "JWT_ALGORITHM", None)

    if algorithm is None:
        # Auto-detect: if key looks like PEM, use RS256; otherwise HS256
        if isinstance(private_key, str) and private_key.strip().startswith("-----BEGIN"):
            algorithm = "RS256"
        else:
            algorithm = "HS256"

    # For symmetric algorithms, public key = private key
    if algorithm.startswith("HS"):
        public_key = private_key
    else:
        public_key = getattr(django_settings, "JWT_PUBLIC_KEY", None)
        if public_key is None:
            # Try to extract public key from private key for RSA
            try:
                from cryptography.hazmat.primitives import serialization
                from cryptography.hazmat.primitives.serialization import load_pem_private_key

                private_key_obj = load_pem_private_key(
                    private_key.encode() if isinstance(private_key, str) else private_key,
                    password=None,
                )
                public_key = private_key_obj.public_key().public_bytes(
                    encoding=serialization.Encoding.PEM,
                    format=serialization.PublicFormat.SubjectPublicKeyInfo,
                ).decode()
            except Exception:
                raise ValueError(
                    f"JWT_PUBLIC_KEY must be set for {algorithm} algorithm, "
                    "or JWT_PRIVATE_KEY must be a valid PEM-encoded RSA key."
                )

    return JWTSettings(
        private_key=private_key,
        public_key=public_key,
        algorithm=algorithm,
        access_token_expires_in=getattr(
            django_settings, "JWT_ACCESS_TOKEN_EXPIRES_IN", 300
        ),
        refresh_token_expires_in=getattr(
            django_settings, "JWT_REFRESH_TOKEN_EXPIRES_IN", 604800
        ),
        validate_session=getattr(
            django_settings, "JWT_VALIDATE_SESSION", True
        ),
        rotate_refresh_token=getattr(
            django_settings, "JWT_ROTATE_REFRESH_TOKEN", True
        ),
    )
