"""
GUARDiA ITSM — API Rate Limiting (Enhancement F-3)

기능:
  1. SlowAPI 기반 FastAPI 미들웨어 통합
  2. IP 기반 기본 제한 + JWT 사용자 식별 제한
  3. 엔드포인트별 차등 제한 설정
  4. Redis 백엔드 (미설치 시 메모리 폴백)
  5. X-RateLimit-* 응답 헤더 자동 추가
  6. 429 Too Many Requests 시 재시도 안내

제한 설정:
  - 기본: 60 req/min per IP
  - 로그인: 10 req/min per IP  (brute-force 방지)
  - 일반 API: 120 req/min per user
  - AI/LLM 엔드포인트: 10 req/min per user (비용 보호)
  - 파일 업로드: 20 req/min per user

사용 예::
    from core.ratelimit import limiter, DEFAULT_LIMIT

    @router.get("/items")
    @limiter.limit(DEFAULT_LIMIT)
    async def list_items(request: Request, ...):
        ...
"""
from __future__ import annotations

import logging
import os
from typing import Callable, Optional

logger = logging.getLogger(__name__)

# ── 제한 상수 ─────────────────────────────────────────────────────────────────
DEFAULT_LIMIT      = "120/minute"    # 일반 API (인증된 사용자)
STRICT_LIMIT       = "60/minute"     # 기본 IP 제한
LOGIN_LIMIT        = "10/minute"     # 로그인 엔드포인트
AI_LIMIT           = "10/minute"     # LLM/AI 엔드포인트
UPLOAD_LIMIT       = "20/minute"     # 파일 업로드
ADMIN_LIMIT        = "300/minute"    # ADMIN 사용자 (완화)

# ── SlowAPI 초기화 ────────────────────────────────────────────────────────────

_limiter: Optional[object] = None


def _get_real_ip(request: object) -> str:
    """
    클라이언트 실제 IP 추출.
    리버스 프록시(X-Forwarded-For) 우선, 없으면 직접 IP.
    """
    forwarded = getattr(getattr(request, "headers", None), "get", lambda k: None)("X-Forwarded-For")
    if forwarded:
        return forwarded.split(",")[0].strip()
    client = getattr(request, "client", None)
    if client:
        return getattr(client, "host", "unknown")
    return "unknown"


def _get_user_key(request: object) -> str:
    """
    Rate limit 키 결정.
    Authorization 헤더에서 JWT sub(사용자명)을 추출하여 사용.
    없으면 IP 주소로 폴백.
    """
    auth = getattr(getattr(request, "headers", None), "get", lambda k: None)("Authorization")
    if auth and auth.startswith("Bearer "):
        try:
            from jose import jwt
            from core.auth import SECRET_KEY, ALGORITHM
            payload = jwt.decode(auth[7:], SECRET_KEY, algorithms=[ALGORITHM])
            sub = payload.get("sub")
            if sub:
                return f"user:{sub}"
        except Exception:
            pass
    return f"ip:{_get_real_ip(request)}"


def create_limiter():
    """SlowAPI 리미터 생성. slowapi 미설치 시 더미 리미터 반환."""
    global _limiter
    if _limiter is not None:
        return _limiter

    try:
        from slowapi import Limiter
        from slowapi.util import get_remote_address

        # Redis 사용 시 slowapi storage URL 설정
        redis_url = os.environ.get("REDIS_URL", "")
        storage_uri = redis_url if redis_url and "redis" in redis_url else "memory://"

        _limiter = Limiter(
            key_func=_get_user_key,
            default_limits=[STRICT_LIMIT],
            storage_uri=storage_uri,
            strategy="fixed-window",
        )
        logger.info("Rate limiter 초기화: storage=%s", storage_uri)
        return _limiter

    except ImportError:
        logger.info("slowapi 미설치 — Rate limiting 비활성화 (더미 리미터 사용)")
        _limiter = _DummyLimiter()
        return _limiter


class _DummyLimiter:
    """slowapi 미설치 시 사용하는 no-op 리미터."""

    def limit(self, limit_str: str, *args, **kwargs):
        """데코레이터 호출 시 그냥 원본 함수 반환."""
        def decorator(func: Callable) -> Callable:
            return func
        return decorator

    def shared_limit(self, *args, **kwargs):
        def decorator(func: Callable) -> Callable:
            return func
        return decorator


# ── 싱글톤 접근 ───────────────────────────────────────────────────────────────
limiter = create_limiter()


# ── FastAPI 앱 통합 헬퍼 ──────────────────────────────────────────────────────

def setup_rate_limiting(app) -> None:
    """
    FastAPI 앱에 SlowAPI 미들웨어 및 예외 핸들러 등록.

    main.py 의 앱 생성 직후 호출::
        from core.ratelimit import setup_rate_limiting
        setup_rate_limiting(app)
    """
    try:
        from slowapi import _rate_limit_exceeded_handler
        from slowapi.errors import RateLimitExceeded
        from slowapi.middleware import SlowAPIMiddleware

        app.state.limiter = limiter
        app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
        app.add_middleware(SlowAPIMiddleware)
        logger.info("SlowAPI Rate Limiting 미들웨어 등록 완료")

    except ImportError:
        logger.info("slowapi 미설치 — Rate Limiting 미들웨어 스킵")
    except Exception as exc:
        logger.warning("Rate Limiting 설정 실패 (무시): %s", exc)


# ── 관리자 API: 현재 제한 상태 조회 ──────────────────────────────────────────

async def get_rate_limit_status(user_key: str) -> dict:
    """특정 사용자/IP의 현재 Rate Limit 상태 조회 (관리자 전용)."""
    try:
        from slowapi import Limiter
        if isinstance(limiter, _DummyLimiter):
            return {"status": "disabled", "message": "slowapi 미설치"}

        return {
            "status":  "enabled",
            "key":     user_key,
            "limits": {
                "default": DEFAULT_LIMIT,
                "login":   LOGIN_LIMIT,
                "ai":      AI_LIMIT,
                "upload":  UPLOAD_LIMIT,
            },
        }
    except Exception:
        return {"status": "unknown"}
