"""
Module d'analyse des technologies web modernes pour Web Sentinel.
Détecte les frameworks SPA, PWA, et leurs configurations de sécurité.
Version simplifiée avec localisation complète.
"""

from __future__ import annotations

import json
import logging
import re
from typing import Iterable, List
from urllib.parse import urljoin

import requests

from ..model import Finding, ScanRequest

LOGGER = logging.getLogger("web_sentinel.checks.modern_web")

# Signatures de frameworks JavaScript modernes
FRAMEWORK_SIGNATURES = {
    'react': [
        r'react\.development\.js',
        r'react\.production\.min\.js',
        r'data-react',
        r'__REACT_DEVTOOLS_GLOBAL_HOOK__',
    ],
    'vue': [
        r'vue\.js',
        r'vue\.min\.js',
        r'data-v-',
        r'__VUE__',
    ],
    'angular': [
        r'angular\.js',
        r'angular\.min\.js',
        r'ng-',
        r'data-ng-',
    ],
}

# Fichiers de configuration à vérifier
CONFIG_FILES = [
    'manifest.json',        # PWA manifest
    'sw.js',               # Service Worker
    'service-worker.js',   # Service Worker alternatif
]


def evaluate_modern_web_technologies(request: ScanRequest) -> Iterable[Finding]:
    """
    Analyse les technologies web modernes et leurs configurations de sécurité.
    """
    findings: List[Finding] = []
    base_url = f"https://{request.domain}"
    
    # Analyse de la page principale
    try:
        response = requests.get(
            base_url,
            headers={"User-Agent": request.user_agent},
            timeout=request.timeout,
            allow_redirects=True
        )
        
        findings.extend(_detect_frameworks(response))
        findings.extend(_check_spa_security(response))
        
    except requests.RequestException as exc:
        findings.append(
            Finding(
                check="modern-web",
                title="Cannot analyze modern web technologies",
                severity="medium",
                description=f"Failed to fetch main page for analysis: {exc}",
                remediation="Verify site accessibility and try again.",
                evidence=f"URL: {base_url}",
                i18n_key="modern.analysis_failed",
                i18n_params={"error": str(exc), "url": base_url}
            )
        )
        return findings
    
    # Analyse des fichiers de configuration
    findings.extend(_analyze_config_files(request))
    
    return findings


def _detect_frameworks(response: requests.Response) -> List[Finding]:
    """
    Détecte les frameworks JavaScript utilisés.
    """
    findings: List[Finding] = []
    content = response.text.lower()
    detected_frameworks = []
    
    for framework, signatures in FRAMEWORK_SIGNATURES.items():
        for signature in signatures:
            if re.search(signature, content, re.IGNORECASE):
                detected_frameworks.append(framework)
                break
    
    if detected_frameworks:
        frameworks_str = ', '.join(detected_frameworks)
        findings.append(
            Finding(
                check="modern-web",
                title="JavaScript frameworks detected",
                severity="info",
                description=f"Detected frameworks: {frameworks_str}",
                remediation="Ensure frameworks are up-to-date and securely configured.",
                evidence=f"Frameworks: {frameworks_str}",
                impact="Framework-specific security considerations may apply.",
                i18n_key="modern.frameworks_detected",
                i18n_params={"frameworks": frameworks_str}
            )
        )
        
        # Vérifications spécifiques aux frameworks
        if 'react' in detected_frameworks and 'react.development.js' in content:
            findings.append(
                Finding(
                    check="modern-web",
                    title="React development build detected",
                    severity="medium",
                    description="React is running in development mode in production",
                    remediation="Use production build of React (react.production.min.js).",
                    evidence="react.development.js found in page",
                    impact="Development builds expose debugging information and have worse performance.",
                    i18n_key="modern.react_dev_build",
                )
            )
    
    return findings


def _check_spa_security(response: requests.Response) -> List[Finding]:
    """
    Vérifications de sécurité spécifiques aux Single Page Applications.
    """
    findings: List[Finding] = []
    content = response.text
    
    # Vérification des tokens/clés exposés dans le code client
    sensitive_patterns = {
        'api key': r'["\']?api[_-]?key["\']?\s*[:=]\s*["\'][^"\']{16,}["\']',
        'secret': r'["\']?secret["\']?\s*[:=]\s*["\'][^"\']{16,}["\']',
        'token': r'["\']?token["\']?\s*[:=]\s*["\'][^"\']{20,}["\']',
    }
    
    for pattern_name, pattern in sensitive_patterns.items():
        matches = re.findall(pattern, content, re.IGNORECASE)
        if matches:
            findings.append(
                Finding(
                    check="modern-web",
                    title=f"Potential {pattern_name} exposed in client code",
                    severity="high",
                    description=f"Client-side code may contain {pattern_name} information",
                    remediation="Move sensitive credentials to server-side code and use environment variables.",
                    evidence=f"Found {len(matches)} potential matches",
                    impact="Exposed credentials can be extracted by anyone viewing the page source.",
                    i18n_key="modern.credentials_exposed",
                    i18n_params={"pattern_name": pattern_name, "count": len(matches)}
                )
            )
    
    return findings


def _analyze_config_files(request: ScanRequest) -> List[Finding]:
    """
    Analyse les fichiers de configuration modernes.
    """
    findings: List[Finding] = []
    base_url = f"https://{request.domain}"
    
    # Vérification du manifest PWA
    manifest_url = urljoin(base_url, 'manifest.json')
    try:
        response = requests.get(
            manifest_url,
            headers={"User-Agent": request.user_agent},
            timeout=request.timeout
        )
        
        if response.status_code == 200:
            findings.append(
                Finding(
                    check="modern-web",
                    title="PWA manifest detected",
                    severity="info",
                    description="Progressive Web App manifest found",
                    remediation="Ensure PWA security best practices are followed.",
                    evidence=f"Manifest available at: {manifest_url}",
                    impact="PWA capabilities require additional security considerations.",
                    i18n_key="modern.pwa_detected",
                    i18n_params={"url": manifest_url}
                )
            )
            
            # Analyse du contenu du manifest
            try:
                manifest = response.json()
                scope = manifest.get('scope', '')
                
                # Vérification du scope trop permissif
                if scope == '/' or not scope:
                    findings.append(
                        Finding(
                            check="modern-web",
                            title="PWA scope too permissive",
                            severity="medium",
                            description="PWA scope allows access to entire domain",
                            remediation="Restrict PWA scope to specific application paths.",
                            evidence=f"Scope: '{scope}'",
                            impact="Broad scope may allow PWA to intercept unintended resources.",
                            i18n_key="modern.pwa_scope_permissive",
                            i18n_params={"scope": scope}
                        )
                    )
                
            except (json.JSONDecodeError, ValueError):
                findings.append(
                    Finding(
                        check="modern-web",
                        title="Invalid PWA manifest format",
                        severity="low",
                        description="PWA manifest file contains invalid JSON",
                        remediation="Fix JSON syntax errors in manifest.json.",
                        evidence="JSON parsing failed",
                        impact="Invalid manifest may prevent PWA installation.",
                        i18n_key="modern.pwa_invalid_manifest",
                    )
                )
        
    except requests.RequestException:
        pass
    
    return findings