import time
from collections import defaultdict
from datetime import datetime, timedelta
import logging
from flask import request, jsonify
from functools import wraps
from config import Config

logger = logging.getLogger(__name__)

class RateLimiter:
    """Rate limiter berbasis memory dengan window 24 jam"""
    
    def __init__(self, limit_per_day=20, window_seconds=86400):
        self.limit_per_day = limit_per_day
        self.window_seconds = window_seconds
        self.requests = defaultdict(list)  # IP -> list of timestamps
    
    def is_whitelisted(self, ip_address: str) -> bool:
        """Cek apakah IP ada di whitelist (unlimited access)"""
        return ip_address in Config.IP_WHITELIST
    
    def is_allowed(self, ip_address: str) -> bool:
        """Cek apakah IP masih diperbolehkan request"""
        # Whitelisted IP = unlimited
        if self.is_whitelisted(ip_address):
            return True
        
        now = time.time()
        cutoff = now - self.window_seconds
        
        # Bersihkan request lama
        if ip_address in self.requests:
            self.requests[ip_address] = [t for t in self.requests[ip_address] if t > cutoff]
        
        # Cek limit
        if len(self.requests.get(ip_address, [])) >= self.limit_per_day:
            return False
        
        # Tambahkan request baru
        if ip_address not in self.requests:
            self.requests[ip_address] = []
        self.requests[ip_address].append(now)
        
        return True
    
    def get_remaining(self, ip_address: str) -> int:
        """Dapatkan sisa request yang tersisa"""
        # Whitelisted IP = unlimited
        if self.is_whitelisted(ip_address):
            return float('inf')  # Unlimited
        
        now = time.time()
        cutoff = now - self.window_seconds
        
        if ip_address in self.requests:
            self.requests[ip_address] = [t for t in self.requests[ip_address] if t > cutoff]
            return max(0, self.limit_per_day - len(self.requests[ip_address]))
        
        return self.limit_per_day
    
    def get_reset_time(self, ip_address: str) -> datetime:
        """Dapatkan waktu reset rate limit"""
        # Whitelisted IP tidak perlu reset
        if self.is_whitelisted(ip_address):
            return datetime.now()
        
        now = time.time()
        cutoff = now - self.window_seconds
        
        if ip_address in self.requests:
            self.requests[ip_address] = [t for t in self.requests[ip_address] if t > cutoff]
            if self.requests[ip_address]:
                oldest = min(self.requests[ip_address])
                return datetime.fromtimestamp(oldest + self.window_seconds)
        
        return datetime.fromtimestamp(now + self.window_seconds)
    
    def get_rate_limit_info(self, ip_address: str) -> dict:
        """Dapatkan info rate limit untuk IP"""
        is_whitelisted = self.is_whitelisted(ip_address)
        
        if is_whitelisted:
            return {
                'limit': 'unlimited',
                'remaining': 'unlimited',
                'is_whitelisted': True,
                'message': 'IP terdaftar di whitelist, akses tanpa batas'
            }
        
        remaining = self.get_remaining(ip_address)
        reset_time = self.get_reset_time(ip_address)
        
        return {
            'limit': self.limit_per_day,
            'remaining': remaining,
            'reset_at': reset_time.isoformat(),
            'reset_in_seconds': max(0, int((reset_time - datetime.now()).total_seconds())),
            'is_whitelisted': False,
            'message': f'Sisa {remaining} request dari {self.limit_per_day} per hari'
        }


# Singleton instance
_rate_limiter = None

def get_rate_limiter():
    global _rate_limiter
    if _rate_limiter is None:
        from config import Config
        _rate_limiter = RateLimiter(
            limit_per_day=Config.RATE_LIMIT_PER_DAY,
            window_seconds=Config.RATE_LIMIT_WINDOW
        )
    return _rate_limiter


def rate_limit_decorator(f):
    """Decorator untuk rate limiting dengan whitelist IP"""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        limiter = get_rate_limiter()
        
        # Dapatkan IP client
        client_ip = request.remote_addr
        forwarded_for = request.headers.get('X-Forwarded-For')
        if forwarded_for:
            client_ip = forwarded_for.split(',')[0].strip()
        
        # Cek whitelist dulu
        is_whitelisted = limiter.is_whitelisted(client_ip)
        
        # Jika tidak di whitelist, cek rate limit
        if not is_whitelisted:
            if not limiter.is_allowed(client_ip):
                reset_time = limiter.get_reset_time(client_ip)
                
                return jsonify({
                    'success': False,
                    'error': 'Rate limit exceeded',
                    'message': f'Anda telah mencapai batas {limiter.limit_per_day} request per hari',
                    'reset_at': reset_time.isoformat(),
                    'reset_in_seconds': max(0, int((reset_time - datetime.now()).total_seconds())),
                    'is_whitelisted': False
                }), 429
        
        # Eksekusi endpoint
        info = limiter.get_rate_limit_info(client_ip)
        response = f(*args, **kwargs)
        
        # Jika response adalah tuple, handle dengan baik
        if isinstance(response, tuple):
            data, status_code = response[0], response[1] if len(response) > 1 else 200
            if isinstance(data, dict):
                data['rate_limit'] = info
            return data, status_code
        
        # Jika response adalah dict, tambahkan rate limit info
        if isinstance(response, dict):
            response['rate_limit'] = info
            return response
        
        return response
    
    return decorated_function