"""In-memory token-bucket rate limiter for the Graph API Gateway.

Applies per-tenant rate limits based on license tier. Uses an in-memory
counter with minute/day windows — upgrade to Redis for multi-process.
"""

from __future__ import annotations

import time
from collections import defaultdict
from typing import Dict, Tuple


class RateLimiter:
    """Per-tenant rate limiter using in-memory sliding window counters."""

    TIER_LIMITS: Dict[str, Dict[str, int]] = {
        "CE": {"rpm": 60, "rpd": 1000},
        "PRO": {"rpm": 300, "rpd": 10000},
        "ENTERPRISE": {"rpm": 1000, "rpd": 100000},
        # Aliases
        "Pro": {"rpm": 300, "rpd": 10000},
        "Enterprise": {"rpm": 1000, "rpd": 100000},
        "FULL": {"rpm": 1000, "rpd": 100000},
    }

    def __init__(self):
        # {tenant_id: (minute_count, minute_start, day_count, day_start)}
        self._counters: Dict[str, list] = defaultdict(lambda: [0, 0.0, 0, 0.0])

    async def check(self, tenant_id: str, tool_id: str) -> bool:
        """Check rate limit for a tenant. Returns True if limit EXCEEDED.

        Args:
            tenant_id: The tenant making the request.
            tool_id: The tool being invoked (for future per-tool limits).

        Returns:
            True if the request should be rejected (429).
        """
        now = time.time()
        counter = self._counters[tenant_id]

        # Reset minute window if expired
        if now - counter[1] >= 60:
            counter[0] = 0
            counter[1] = now

        # Reset day window if expired
        if now - counter[3] >= 86400:
            counter[2] = 0
            counter[3] = now

        # Look up limits — default to CE
        limits = self.TIER_LIMITS.get("CE", {"rpm": 60, "rpd": 1000})

        # Try to find tenant tier from counters metadata or use CE
        # In practice, the tier comes from RequestContext; we store it
        # on first check. For simplicity, we use CE defaults here and
        # the ToolRegistry calls check() after resolving the tier.
        # The tier-aware version below is used by set_tier().

        rpm = limits["rpm"]
        rpd = limits["rpd"]

        if counter[0] >= rpm or counter[2] >= rpd:
            return True  # Exceeded

        counter[0] += 1
        counter[2] += 1
        return False

    def set_tier(self, tenant_id: str, tier: str) -> None:
        """Pre-register a tenant's tier for accurate rate limiting."""
        # Store tier info for the tenant (future enhancement)
        pass

    def get_usage(self, tenant_id: str) -> Dict[str, int]:
        """Return current usage counters for a tenant."""
        counter = self._counters.get(tenant_id, [0, 0.0, 0, 0.0])
        return {
            "requests_this_minute": counter[0],
            "requests_today": counter[2],
        }
