"""
Common decorators used throughout the application
"""
import time
import json
import logging
from functools import wraps
from flask import request, jsonify, make_response
from security import encrypt_data as original_encrypt_data


logger = logging.getLogger(__name__)

# Cache for API key validation results
api_key_cache = {}
API_KEY_CACHE_TTL = 300  # 5 minutes cache TTL


def require_api_key(f):
    """Decorator to enforce API key authentication from headers only."""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        # Allow OPTIONS requests to pass through for CORS preflight
        if request.method == 'OPTIONS':
            return f(*args, **kwargs)
            
        # Get client IP for rate limiting
        client_ip = request.remote_addr
        
        # Only accept API key from headers for security
        api_key = request.headers.get('X-API-KEY') or request.headers.get('api_key')
        
        if not api_key:
            logger.warning("Missing API key attempt from {}".format(client_ip))
            return jsonify({
                "response": "failure", 
                "error": "API key must be provided in X-API-KEY header"
            }), 401
        
        # Check cache first (IP + API key combination)
        cache_key = "{}:{}:{}".format(client_ip, request.path, api_key[:8])
        cached_result = api_key_cache.get(cache_key)
        
        current_time = time.time()
        if cached_result and (current_time - cached_result['timestamp'] < 300):
            if not cached_result['valid']:
                return jsonify({"response": "failure", "error": "Invalid API key"}), 401
        else:
            try:
                from config.config_settings import ALLOWED_KEYS
                is_valid = api_key in ALLOWED_KEYS
            except ImportError:
                is_valid = False
            
            api_key_cache[cache_key] = {'valid': is_valid, 'timestamp': current_time}
            
            if len(api_key_cache) > 1000:
                oldest_keys = sorted(api_key_cache.keys(), key=lambda k: api_key_cache[k]['timestamp'])[:200]
                for key in oldest_keys: api_key_cache.pop(key, None)
            
            if not is_valid:
                logger.warning("Invalid API key attempt from {}".format(client_ip))
                return jsonify({"response": "failure", "error": "Invalid API key"}), 401
        
        return f(*args, **kwargs)
    return decorated_function


def require_admin(f):
    """Decorator to enforce admin-level access (requires API key first)"""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        api_key = request.headers.get('X-API-KEY') or request.headers.get('api_key')
        if not api_key:
            return jsonify({"response": "failure", "error": "Admin access requires API key"}), 401
        
        try:
            from config.config_settings import ALLOWED_KEYS
            key_permissions = ALLOWED_KEYS.get(api_key, {})
            permissions = key_permissions.get('permissions', [])
            if 'admin' not in permissions:
                logger.warning(f"Non-admin API key attempted admin action: {request.path}")
                return jsonify({"response": "failure", "error": "Admin access required"}), 403
        except ImportError:
            return jsonify({"response": "failure", "error": "Access denied"}), 403
        
        return f(*args, **kwargs)
    return decorated_function


def encrypt_response(f):
    """Decorator to mark a route's response for encryption."""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        response = f(*args, **kwargs)
        
        if isinstance(response, tuple) and len(response) >= 2:
            data, status_code = response[0], response[1]
            headers = response[2] if len(response) >= 3 else {}
            from flask import Response
            if isinstance(data, Response):
                data.status_code, response = status_code, data
                for k, v in headers.items(): data.headers[k] = v
            else:
                response = make_response(jsonify(data), status_code, headers)
        elif isinstance(response, dict):
            response = make_response(jsonify(response), 200)
            
        if hasattr(response, 'headers'):
            setattr(response, '_encrypt_response', True)
        else:
            logger.warning("Cannot encrypt non-Response object: {}".format(type(response)))
        return response
    return decorated_function


def add_keep_alive(response):
    """Add keep-alive headers to response for connection reuse."""
    # response.headers['Connection'] = 'keep-alive'
    # response.headers['Keep-Alive'] = 'timeout=60, max=1000'
    # Add cache control headers for static responses
    if request.path.startswith('/static/'):
        response.headers['Cache-Control'] = 'public, max-age=86400'  # 24 hours
    return response