from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.datastructures import MutableHeaders
from typing import Callable

class LanguageMiddleware(BaseHTTPMiddleware):
    """
    Middleware to detect and set user's preferred language
    Supports detection from:
    1. Query parameter: ?language=ko
    2. Header: Accept-Language or X-Language
    3. Cookie: language
    """
    
    def __init__(self, app, supported_languages=None):
        super().__init__(app)
        self.supported_languages = supported_languages or ['en', 'ko']
        self.default_language = 'en'
    
    async def dispatch(self, request: Request, call_next: Callable):
        """
        Process request and detect language preference
        """
        language = self.detect_language(request)
        
        # Store language in request state for access in endpoints
        request.state.language = language
        
        # Process request
        response = await call_next(request)
        
        # Add language to response headers for client reference
        response.headers['Content-Language'] = language
        
        return response
    
    def detect_language(self, request: Request) -> str:
        """
        Detect user's preferred language from various sources
        Priority: Query param > Header > Cookie > Default
        """
        # 1. Check query parameter
        language = request.query_params.get('language')
        if language and language in self.supported_languages:
            return language
        
        # 2. Check custom X-Language header
        language = request.headers.get('X-Language')
        if language and language in self.supported_languages:
            return language
        
        # 3. Check Accept-Language header
        accept_language = request.headers.get('Accept-Language')
        if accept_language:
            language = self.parse_accept_language(accept_language)
            if language:
                return language
        
        # 4. Check cookie
        language = request.cookies.get('language')
        if language and language in self.supported_languages:
            return language
        
        # 5. Return default language
        return self.default_language
    
    def parse_accept_language(self, accept_language: str) -> str:
        """
        Parse Accept-Language header and return best matching language
        Example: 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7'
        """
        languages = []
        
        for lang_entry in accept_language.split(','):
            parts = lang_entry.strip().split(';')
            lang_code = parts[0].strip().lower()
            
            # Extract base language code (e.g., 'ko' from 'ko-KR')
            base_lang = lang_code.split('-')[0]
            
            # Get quality value (default 1.0)
            quality = 1.0
            if len(parts) > 1 and 'q=' in parts[1]:
                try:
                    quality = float(parts[1].split('=')[1])
                except (ValueError, IndexError):
                    quality = 1.0
            
            languages.append((base_lang, quality))
        
        # Sort by quality (highest first)
        languages.sort(key=lambda x: x[1], reverse=True)
        
        # Return first supported language
        for lang, _ in languages:
            if lang in self.supported_languages:
                return lang
        
        return None


def get_language_from_request(request: Request) -> str:
    """
    Helper function to get language from request state
    """
    return getattr(request.state, 'language', 'en')