#!/usr/bin/env python3
"""
Proxy CORS multi-machines OCPP + serveur web intégré
Accès réseau : http://<<IP_DE_TA_MACHINE>:5005/
"""

import http.server
import socketserver
import urllib.request
import urllib.error
import json
import re
import os
import mimetypes

# ============ CONFIGURATION ============
PROXY_PORT = 5005
HTML_FILE = "/var/www/html/logs/db-explorer.html"  # Chemin vers ton HTML

DEFAULT_MACHINES = {}
# ========================================


class MultiMachineProxy(http.server.BaseHTTPRequestHandler):
    
    def log_message(self, format, *args):
        print(f"[{self.log_date_time_string()}] {format % args}")
    
    def _send_cors_headers(self):
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS')
        self.send_header('Access-Control-Allow-Headers', '*')
    
    def do_OPTIONS(self):
        self.send_response(204)
        self._send_cors_headers()
        self.end_headers()
    
    def do_HEAD(self):
        self.do_GET(body=False)
    
    def _parse_path(self):
        path = self.path
        
        # Route spéciale : servir le fichier HTML
        if path == '/' or path == '/index.html':
            return 'html', None, None
        
        # Route : /machine/<host>/<path>
        match = re.match(r'^/machine/([^/]+)(/.*)?$', path)
        if not match:
            return None, None, path
        
        host_or_alias = match.group(1)
        file_path = match.group(2) or '/'
        
        if host_or_alias in DEFAULT_MACHINES:
            target_host = DEFAULT_MACHINES[host_or_alias]
            alias = host_or_alias
        else:
            if ':' not in host_or_alias:
                host_or_alias += ':8080'
            target_host = host_or_alias
            alias = None
        
        target_url = f"http://{target_host}{file_path}"
        return 'proxy', target_host, target_url, alias
    
    def do_GET(self, body=True):
        route_type = self._parse_path()
        
        # Servir le fichier HTML
        if route_type[0] == 'html':
            try:
                with open(HTML_FILE, 'rb') as f:
                    content = f.read()
                self.send_response(200)
                self.send_header('Content-Type', 'text/html; charset=utf-8')
                self._send_cors_headers()
                self.end_headers()
                if body:
                    self.wfile.write(content)
            except FileNotFoundError:
                self._send_error(404, f"Fichier HTML non trouvé: {HTML_FILE}")
            return
        
        # Proxy vers machine OCPP
        if route_type[0] != 'proxy':
            self._send_error(400, "URL invalide. Utilisez / ou /machine/<ip:port>/...")
            return
        
        _, target_host, target_url, alias = route_type
        display_name = alias or target_host
        
        try:
            req = urllib.request.Request(
                target_url,
                headers={'User-Agent': 'OCPP-MultiProxy/1.0'},
                method='GET'
            )
            
            with urllib.request.urlopen(req, timeout=30) as response:
                self.send_response(response.status)
                
                skip_headers = {
                    'transfer-encoding', 'content-encoding',
                    'access-control-allow-origin',
                    'access-control-allow-methods'
                }
                for header, value in response.headers.items():
                    if header.lower() not in skip_headers:
                        self.send_header(header, value)
                
                self._send_cors_headers()
                self.end_headers()
                
                if body:
                    content = response.read()
                    self.wfile.write(content)
                    print(f"  → [{display_name}] Transféré: {len(content)} octets")
        
        except urllib.error.HTTPError as e:
            print(f"  → [{display_name}] Erreur HTTP {e.code}")
            self.send_response(e.code)
            self._send_cors_headers()
            self.end_headers()
            if body:
                self.wfile.write(e.read())
        
        except urllib.error.URLError as e:
            print(f"  → [{display_name}] Connexion impossible: {e.reason}")
            self._send_error(502, f"Impossible de contacter {display_name} ({target_host})", e.reason)
        
        except Exception as e:
            print(f"  → [{display_name}] Erreur: {e}")
            self._send_error(500, f"Erreur proxy: {str(e)}")
    
    def _send_error(self, code, message, detail=""):
        self.send_response(code)
        self.send_header('Content-Type', 'text/html; charset=utf-8')
        self._send_cors_headers()
        self.end_headers()
        
        html = f"""<!DOCTYPE html>
<html><head><title>Erreur {code}</title>
<style>
body {{ font-family: sans-serif; padding: 40px; max-width: 600px; margin: 0 auto; }}
h1 {{ color: #ef4444; }}
code {{ background: #f1f5f9; padding: 2px 6px; border-radius: 4px; }}
.box {{ background: #fef2f2; border: 1px solid #fecaca; padding: 16px; border-radius: 8px; margin: 20px 0; }}
</style></head>
<body>
<h1>❌ Erreur {code}</h1>
<div class="box"><p><strong>{message}</strong></p>{f'<p><small>Détail: {detail}</small></p>' if detail else ''}</div>
<h3>URLs disponibles:</h3>
<ul>
<li><code>http://localhost:{PROXY_PORT}/</code> → Interface web</li>
<li><code>/machine/192.168.100.46:8080/var/ocpp_data/xxx.db</code></li>
</ul>
</body></html>""".encode('utf-8')
        
        self.wfile.write(html)


def main():
    # Détecte l'IP locale pour l'affichage
    import socket
    hostname = socket.gethostname()
    try:
        local_ip = socket.getaddrinfo(hostname, None, socket.AF_INET)[0][4][0]
    except:
        local_ip = "127.0.0.1"
    
    print("=" * 65)
    print("  PROXY CORS MULTI-MACHINES + SERVEUR WEB")
    print("=" * 65)
    print(f"  Interface web : http://{local_ip}:{PROXY_PORT}/")
    print(f"  Proxy API     : http://{local_ip}:{PROXY_PORT}/machine/<ip:port>/...")
    print("-" * 65)
    print("  Accès depuis cette machine :")
    print(f"    http://localhost:{PROXY_PORT}/")
    print("  Accès depuis le réseau local :")
    print(f"    http://{local_ip}:{PROXY_PORT}/")
    print("-" * 65)
    print("  Ctrl+C pour arrêter")
    print("=" * 65)
    print()
    
    with socketserver.TCPServer(("", PROXY_PORT), MultiMachineProxy) as httpd:
        try:
            httpd.serve_forever()
        except KeyboardInterrupt:
            print("\n\nProxy arrêté.")


if __name__ == "__main__":
    main()
