"""
Güvenlik modülü: Authentication, Rate Limiting, Input Validation
"""
import re
import hashlib
import hmac
import time
from functools import wraps
from flask import request, jsonify, g
from typing import Optional, Dict, List
from collections import defaultdict
from datetime import datetime, timedelta


class SecurityManager:
    """Güvenlik yönetim sınıfı"""
    
    def __init__(self, api_keys: Dict[str, Dict] = None, rate_limit_per_minute: int = 60):
        """
        Args:
            api_keys: API key dict {key: {name, rate_limit, enabled}}
            rate_limit_per_minute: Varsayılan rate limit
        """
        self.api_keys = api_keys or {}
        self.rate_limit_per_minute = rate_limit_per_minute
        # Rate limiting için: {ip_or_key: [(timestamp, ...)]}
        self.rate_limit_store = defaultdict(list)
        # IP bazlı rate limiting
        self.ip_rate_limits = defaultdict(list)
    
    def validate_api_key(self, api_key: Optional[str]) -> tuple[bool, Optional[Dict]]:
        """
        API key doğrula
        
        Returns:
            (is_valid, key_info) tuple
        """
        if not api_key:
            return False, None
        
        # API key'i hash'le ve karşılaştır
        key_info = self.api_keys.get(api_key)
        if key_info and key_info.get('enabled', True):
            return True, key_info
        
        return False, None
    
    def check_rate_limit(self, identifier: str, limit: int = None) -> tuple[bool, int]:
        """
        Rate limit kontrolü
        
        Args:
            identifier: IP adresi veya API key
            limit: Rate limit (None ise varsayılan kullanılır)
        
        Returns:
            (is_allowed, remaining_requests) tuple
        """
        if limit is None:
            limit = self.rate_limit_per_minute
        
        now = time.time()
        minute_ago = now - 60
        
        # Eski kayıtları temizle
        self.rate_limit_store[identifier] = [
            ts for ts in self.rate_limit_store[identifier] if ts > minute_ago
        ]
        
        # Rate limit kontrolü
        if len(self.rate_limit_store[identifier]) >= limit:
            remaining = 0
            return False, remaining
        
        # Yeni isteği kaydet
        self.rate_limit_store[identifier].append(now)
        remaining = limit - len(self.rate_limit_store[identifier])
        
        return True, remaining
    
    def sanitize_input(self, text: str, max_length: int = 500) -> str:
        """
        Input sanitization (XSS koruması)
        
        Args:
            text: Temizlenecek metin
            max_length: Maksimum uzunluk
        
        Returns:
            Temizlenmiş metin
        """
        if not text:
            return ""
        
        # Uzunluk kontrolü
        text = text[:max_length]
        
        # Tehlikeli karakterleri temizle
        # HTML tag'lerini kaldır (basit)
        text = re.sub(r'<[^>]+>', '', text)
        
        # Script tag'lerini kaldır
        text = re.sub(r'<script[^>]*>.*?</script>', '', text, flags=re.IGNORECASE | re.DOTALL)
        
        # JavaScript event handler'ları kaldır
        text = re.sub(r'on\w+\s*=', '', text, flags=re.IGNORECASE)
        
        return text.strip()
    
    def validate_channel_id(self, channel_id: str) -> bool:
        """
        Channel ID formatını doğrula
        
        Args:
            channel_id: YouTube Channel ID
        
        Returns:
            Geçerli mi?
        
        YouTube Channel ID formatı:
        - UC ile başlamalı
        - Toplam 24 karakter (UC + 22 karakter)
        - Sadece alfanumerik karakterler ve alt çizgi (_) içermeli
        - Tire (-) karakteri içermemeli
        """
        if not channel_id:
            return False
        
        # UC ile başlayan, 24 karakter, sadece alfanumerik ve alt çizgi (tire YOK)
        if re.match(r'^UC[a-zA-Z0-9_]{22}$', channel_id):
            # Double check: Tire karakteri içermemeli
            if '-' not in channel_id:
                return True
        
        return False
    
    def validate_channel_handle(self, handle: str) -> bool:
        """
        Channel handle formatını doğrula
        
        Args:
            handle: @username veya username
        
        Returns:
            Geçerli mi?
        """
        if not handle:
            return False
        
        # @ ile başlayan veya başlamayan, alfanumerik + _ - karakterler
        handle = handle.lstrip('@')
        if re.match(r'^[a-zA-Z0-9_-]{1,30}$', handle):
            return True
        
        return False
    
    def validate_url(self, url: str) -> bool:
        """
        URL formatını doğrula
        
        Args:
            url: URL string
        
        Returns:
            Geçerli mi?
        """
        if not url:
            return False
        
        # Sadece YouTube URL'lerine izin ver
        youtube_patterns = [
            r'^https?://(www\.)?youtube\.com/channel/[a-zA-Z0-9_-]+',
            r'^https?://(www\.)?youtube\.com/@[a-zA-Z0-9_-]+',
            r'^https?://(www\.)?youtu\.be/[a-zA-Z0-9_-]+',
        ]
        
        for pattern in youtube_patterns:
            if re.match(pattern, url):
                return True
        
        return False
    
    def validate_max_items(self, max_items: int) -> bool:
        """
        max_items parametresini doğrula
        
        Args:
            max_items: Maksimum transcript sayısı (her istekte işlenecek)
        
        Returns:
            Geçerli mi?
        """
        # Maksimum 100 transcript (20'şer batch'ler halinde işlenir)
        return isinstance(max_items, int) and 1 <= max_items <= 100


# Global security manager instance
_security_manager = None


def init_security(api_keys: Dict[str, Dict] = None, rate_limit: int = 60):
    """Security manager'ı initialize et"""
    global _security_manager
    _security_manager = SecurityManager(api_keys, rate_limit)
    return _security_manager


def get_security_manager() -> SecurityManager:
    """Security manager instance'ı al"""
    global _security_manager
    if _security_manager is None:
        _security_manager = SecurityManager()
    return _security_manager


def require_api_key(f):
    """API key gerektiren decorator"""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        security = get_security_manager()
        
        # API key'i header'dan veya query'den al
        api_key_header = request.headers.get('X-API-Key')
        api_key_query = request.args.get('api_key')
        api_key = api_key_header or api_key_query
        
        # Debug logging (sadece query parametresi varsa)
        if api_key_query and not api_key_header:
            import logging
            logger = logging.getLogger(__name__)
            logger.debug(f"[API_KEY] Query parametresinden API key alındı: {api_key_query[:10]}... (uzunluk: {len(api_key_query) if api_key_query else 0})")
        
        is_valid, key_info = security.validate_api_key(api_key)
        
        if not is_valid:
            return jsonify({
                'error': 'Geçersiz veya eksik API key',
                'message': 'X-API-Key header veya api_key query parametresi gerekli'
            }), 401
        
        # Rate limit kontrolü (API key bazlı)
        key_rate_limit = key_info.get('rate_limit', security.rate_limit_per_minute)
        is_allowed, remaining = security.check_rate_limit(api_key, key_rate_limit)
        
        if not is_allowed:
            return jsonify({
                'error': 'Rate limit aşıldı',
                'message': f'Dakikada {key_rate_limit} istek limiti',
                'retry_after': 60
            }), 429
        
        # API key bilgisini g context'e ekle
        g.api_key = api_key
        g.api_key_info = key_info
        
        # Response header'a remaining ekle
        g.rate_limit_remaining = remaining
        
        return f(*args, **kwargs)
    
    return decorated_function


def rate_limit(limit_per_minute: int = 60):
    """Rate limiting decorator (IP bazlı)"""
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            security = get_security_manager()
            
            # IP adresini al
            ip_address = request.environ.get('HTTP_X_FORWARDED_FOR', request.remote_addr)
            if ip_address:
                ip_address = ip_address.split(',')[0].strip()
            
            # Rate limit kontrolü
            is_allowed, remaining = security.check_rate_limit(ip_address, limit_per_minute)
            
            if not is_allowed:
                return jsonify({
                    'error': 'Rate limit aşıldı',
                    'message': f'Dakikada {limit_per_minute} istek limiti',
                    'retry_after': 60
                }), 429
            
            g.rate_limit_remaining = remaining
            
            return f(*args, **kwargs)
        return decorated_function
    return decorator


def validate_input(f):
    """Input validation decorator"""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        security = get_security_manager()
        
        # Query parametrelerini validate et
        channel_id = request.args.get('channel_id')
        channel = request.args.get('channel')
        channel_url = request.args.get('channel_url')
        max_items = request.args.get('max_items', '50')
        
        # Channel ID validation
        if channel_id and not security.validate_channel_id(channel_id):
            return jsonify({
                'error': 'Geçersiz channel_id formatı',
                'message': 'Channel ID UC ile başlayan 24 karakter olmalı'
            }), 400
        
        # Channel handle validation
        if channel and not security.validate_channel_handle(channel):
            return jsonify({
                'error': 'Geçersiz channel handle formatı',
                'message': 'Channel handle alfanumerik karakterler içermeli (maks 30 karakter)'
            }), 400
        
        # Channel URL validation
        if channel_url and not security.validate_url(channel_url):
            return jsonify({
                'error': 'Geçersiz channel_url formatı',
                'message': 'Sadece YouTube URL\'lerine izin verilir'
            }), 400
        
        # max_items validation
        try:
            max_items_int = int(max_items)
            if not security.validate_max_items(max_items_int):
                return jsonify({
                    'error': 'Geçersiz max_items değeri',
                    'message': 'max_items 1-100 arasında olmalı (20\'şer batch\'ler halinde işlenir)'
                }), 400
        except ValueError:
            return jsonify({
                'error': 'Geçersiz max_items formatı',
                'message': 'max_items sayı olmalı'
            }), 400
        
        # Input sanitization
        if channel_id:
            channel_id = security.sanitize_input(channel_id, max_length=50)
        if channel:
            channel = security.sanitize_input(channel, max_length=50)
        if channel_url:
            channel_url = security.sanitize_input(channel_url, max_length=200)
        
        return f(*args, **kwargs)
    
    return decorated_function

