from __future__ import annotations

from django.conf import settings
from django.core.cache import cache

from .constants import (
    DEFAULT_ADMIN_THROTTLE_LIMIT,
    DEFAULT_ADMIN_THROTTLE_WINDOW_SECONDS,
    DEFAULT_PUBLIC_THROTTLE_LIMIT,
    DEFAULT_PUBLIC_THROTTLE_WINDOW_SECONDS,
    MODE_ADMIN,
)


def get_client_ip(request) -> str:
    forwarded_for = (request.META.get("HTTP_X_FORWARDED_FOR") or "").strip()
    if forwarded_for:
        return forwarded_for.split(",")[0].strip()
    return (request.META.get("REMOTE_ADDR") or "").strip() or "unknown"


def get_throttle_config(mode: str) -> tuple[int, int]:
    if mode == MODE_ADMIN:
        return (
            getattr(
                settings,
                "AI_ASSISTANT_ADMIN_THROTTLE_LIMIT",
                DEFAULT_ADMIN_THROTTLE_LIMIT,
            ),
            getattr(
                settings,
                "AI_ASSISTANT_ADMIN_THROTTLE_WINDOW_SECONDS",
                DEFAULT_ADMIN_THROTTLE_WINDOW_SECONDS,
            ),
        )
    return (
        getattr(
            settings,
            "AI_ASSISTANT_PUBLIC_THROTTLE_LIMIT",
            DEFAULT_PUBLIC_THROTTLE_LIMIT,
        ),
        getattr(
            settings,
            "AI_ASSISTANT_PUBLIC_THROTTLE_WINDOW_SECONDS",
            DEFAULT_PUBLIC_THROTTLE_WINDOW_SECONDS,
        ),
    )


def build_throttle_key(
    *,
    mode: str,
    site_id: int,
    session_id: str,
    visitor_id: str,
    user_id: int | None,
    client_ip: str,
) -> str:
    identity = session_id or visitor_id or (str(user_id) if user_id else "")
    return f"ai_assistant:throttle:{mode}:{site_id}:{identity}:{client_ip}"


def check_and_increment_throttle(
    *,
    mode: str,
    site_id: int,
    session_id: str,
    visitor_id: str,
    user_id: int | None,
    client_ip: str,
) -> dict:
    limit, window_seconds = get_throttle_config(mode)
    key = build_throttle_key(
        mode=mode,
        site_id=site_id,
        session_id=session_id,
        visitor_id=visitor_id,
        user_id=user_id,
        client_ip=client_ip,
    )

    added = cache.add(key, 1, timeout=window_seconds)
    if added:
        return {"allowed": True, "limit": limit, "retry_after": window_seconds}

    try:
        count = cache.incr(key)
    except ValueError:
        cache.set(key, 1, timeout=window_seconds)
        count = 1

    allowed = count <= limit
    return {
        "allowed": allowed,
        "limit": limit,
        "retry_after": window_seconds,
    }
