#!/usr/bin/env python3
"""
Web Sentinel Local Proxy Server
Serveur local qui expose une API REST simple pour les IDEs
et forward les requêtes vers l'API Web Sentinel distante.
"""

import json
import os
import tempfile
from pathlib import Path
from typing import Dict, Any, Optional
from flask import Flask, request, jsonify, Response
from flask_cors import CORS
import requests
import logging

# Configuration
LOCAL_PORT = 8765
API_URL = os.getenv('WEB_SENTINEL_API_URL', 'https://api.web-sentinel.com')
CONFIG_FILE = Path.home() / '.websentinel' / 'config.json'

app = Flask(__name__)
CORS(app)  # Permettre les requêtes cross-origin pour les IDEs

# Configuration du logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class WebSentinelProxy:
    """Proxy local pour Web Sentinel."""
    
    def __init__(self):
        self.config = self.load_config()
        
    def load_config(self) -> Dict[str, Any]:
        """Charger la configuration locale."""
        if CONFIG_FILE.exists():
            try:
                with open(CONFIG_FILE, 'r') as f:
                    return json.load(f)
            except Exception as e:
                logger.warning(f"Erreur lecture config: {e}")
        
        # Configuration par défaut
        return {
            'api_url': API_URL,
            'api_key': os.getenv('WEB_SENTINEL_API_KEY'),
            'cache_enabled': True,
            'cache_ttl': 300  # 5 minutes
        }
    
    def save_config(self):
        """Sauvegarder la configuration."""
        CONFIG_FILE.parent.mkdir(exist_ok=True)
        with open(CONFIG_FILE, 'w') as f:
            json.dump(self.config, f, indent=2)
    
    async def scan_content(self, content: str, file_path: str, language: str = 'auto') -> Dict[str, Any]:
        """Scanner du contenu de fichier."""
        if not self.config.get('api_key'):
            raise ValueError("Clé API manquante")
        
        payload = {
            'source_content': content,
            'file_path': file_path,
            'language': language,
            'api_key': self.config['api_key'],
            'options': {
                'severity_min': 'medium',
                'detailed_report': True
            }
        }
        
        try:
            response = requests.post(
                f"{self.config['api_url']}/api/v1/scan-source",
                json=payload,
                headers={'User-Agent': 'Web-Sentinel-Proxy/1.0'},
                timeout=30
            )
            response.raise_for_status()
            return response.json()
            
        except requests.RequestException as e:
            logger.error(f"Erreur API: {e}")
            raise

proxy = WebSentinelProxy()

@app.route('/health')
def health():
    """Endpoint de santé."""
    return jsonify({
        'status': 'healthy',
        'version': '1.0.0',
        'api_configured': bool(proxy.config.get('api_key'))
    })

@app.route('/config', methods=['GET'])
def get_config():
    """Récupérer la configuration (sans la clé API)."""
    config = proxy.config.copy()
    if 'api_key' in config:
        config['api_key'] = '***' if config['api_key'] else None
    return jsonify(config)

@app.route('/config', methods=['POST'])
def update_config():
    """Mettre à jour la configuration."""
    data = request.get_json()
    
    if 'api_key' in data:
        proxy.config['api_key'] = data['api_key']
    
    if 'api_url' in data:
        proxy.config['api_url'] = data['api_url']
    
    proxy.save_config()
    
    return jsonify({'status': 'updated'})

@app.route('/scan/content', methods=['POST'])
def scan_content():
    """Scanner du contenu de fichier."""
    data = request.get_json()
    
    if not data or 'content' not in data:
        return jsonify({'error': 'Content required'}), 400
    
    try:
        result = proxy.scan_content(
            content=data['content'],
            file_path=data.get('file_path', 'unknown'),
            language=data.get('language', 'auto')
        )
        
        # Adapter le format pour les IDEs
        findings = []
        for finding in result.get('findings', []):
            findings.append({
                'rule_id': finding.get('check'),
                'message': finding.get('title'),
                'description': finding.get('description'),
                'severity': finding.get('severity'),
                'line': finding.get('line', 1),
                'column': finding.get('column', 1),
                'fix_suggestion': finding.get('remediation')
            })
        
        return jsonify({
            'status': 'success',
            'findings': findings,
            'summary': {
                'total': len(findings),
                'by_severity': {
                    'critical': len([f for f in findings if f['severity'] == 'critical']),
                    'high': len([f for f in findings if f['severity'] == 'high']),
                    'medium': len([f for f in findings if f['severity'] == 'medium']),
                    'low': len([f for f in findings if f['severity'] == 'low'])
                }
            }
        })
        
    except ValueError as e:
        return jsonify({'error': str(e)}), 401
    except Exception as e:
        logger.error(f"Erreur scan: {e}")
        return jsonify({'error': 'Internal server error'}), 500

@app.route('/scan/file', methods=['POST'])
def scan_file():
    """Scanner un fichier local."""
    data = request.get_json()
    
    if not data or 'file_path' not in data:
        return jsonify({'error': 'file_path required'}), 400
    
    file_path = Path(data['file_path'])
    
    if not file_path.exists() or not file_path.is_file():
        return jsonify({'error': 'File not found'}), 404
    
    try:
        content = file_path.read_text(encoding='utf-8')
        
        # Détecter le langage
        language = data.get('language', 'auto')
        if language == 'auto':
            ext = file_path.suffix.lower()
            language_map = {
                '.php': 'php',
                '.js': 'javascript',
                '.ts': 'javascript', 
                '.py': 'python',
                '.java': 'java',
                '.cs': 'csharp',
                '.go': 'go'
            }
            language = language_map.get(ext, 'auto')
        
        # Utiliser l'endpoint scan_content
        request_data = {
            'content': content,
            'file_path': str(file_path),
            'language': language
        }
        
        with app.test_request_context('/scan/content', 
                                    method='POST', 
                                    json=request_data):
            return scan_content()
            
    except Exception as e:
        logger.error(f"Erreur lecture fichier: {e}")
        return jsonify({'error': 'Failed to read file'}), 500

@app.route('/scan/directory', methods=['POST'])
def scan_directory():
    """Scanner tous les fichiers d'un répertoire."""
    data = request.get_json()
    
    if not data or 'directory_path' not in data:
        return jsonify({'error': 'directory_path required'}), 400
    
    directory = Path(data['directory_path'])
    
    if not directory.exists() or not directory.is_dir():
        return jsonify({'error': 'Directory not found'}), 404
    
    # Extensions supportées
    extensions = {'.php', '.js', '.ts', '.py', '.java', '.cs', '.go'}
    exclude_patterns = {'node_modules', 'vendor', 'dist', 'build', '__pycache__', '.git'}
    
    results = []
    
    for file_path in directory.rglob('*'):
        # Ignorer les dossiers exclus
        if any(pattern in str(file_path) for pattern in exclude_patterns):
            continue
            
        if file_path.is_file() and file_path.suffix in extensions:
            try:
                with app.test_request_context('/scan/file',
                                            method='POST',
                                            json={'file_path': str(file_path)}):
                    result = scan_file()
                    
                if result.status_code == 200:
                    scan_data = json.loads(result.data)
                    if scan_data.get('findings'):
                        results.append({
                            'file': str(file_path.relative_to(directory)),
                            'findings': scan_data['findings']
                        })
                        
            except Exception as e:
                logger.warning(f"Erreur scan {file_path}: {e}")
    
    total_findings = sum(len(r['findings']) for r in results)
    
    return jsonify({
        'status': 'success',
        'files_with_issues': len(results),
        'total_findings': total_findings,
        'results': results
    })

if __name__ == '__main__':
    print(f"""
🚀 Web Sentinel Local Proxy Server
🌐 Running on: http://localhost:{LOCAL_PORT}
📋 API Endpoint: {API_URL}
🔧 Config: {CONFIG_FILE}

Usage in your IDE/tools:
- Health: GET http://localhost:{LOCAL_PORT}/health
- Scan content: POST http://localhost:{LOCAL_PORT}/scan/content
- Scan file: POST http://localhost:{LOCAL_PORT}/scan/file  
- Scan directory: POST http://localhost:{LOCAL_PORT}/scan/directory

Set your API key:
curl -X POST http://localhost:{LOCAL_PORT}/config \\
  -H "Content-Type: application/json" \\
  -d '{{"api_key": "YOUR_API_KEY"}}'
    """)
    
    app.run(host='127.0.0.1', port=LOCAL_PORT, debug=False)