import sys
import os
import re
import time
import folium
from selenium import webdriver
from selenium.webdriver.firefox.service import Service as FirefoxService
from selenium.webdriver.firefox.options import Options

def locator_to_latlon(locator):
    """Konvertiert einen Maidenhead-Locator in Breitengrad und Längengrad."""
    locator = locator.strip().upper()
    if not (4 <= len(locator) <= 6):
        return None

    # Felder 1 & 2 (Buchstaben für das Großfeld / Field)
    lon = (ord(locator[0]) - ord('A')) * 20 - 180
    lat = (ord(locator[1]) - ord('A')) * 10 - 90
    
    # Felder 3 & 4 (Zahlen für das Großfeld-Quadrat / Square)
    lon += int(locator[2]) * 2
    lat += int(locator[3])

    # Felder 5 & 6 (Buchstaben für das Kleinfeld / Subsquare)
    if len(locator) == 6:
        lon += (ord(locator[4]) - ord('A') + 0.5) * (2 / 24)
        lat += (ord(locator[5]) - ord('A') + 0.5) * (1 / 24)
    else:
        lon += 1.0
        lat += 0.5

    return lat, lon

def parse_edi_file(file_path):
    """Parst eine .edi Datei und extrahiert QSOs."""
    my_locator = None
    qsos = []

    if not os.path.exists(file_path):
        print(f"Fehler: Datei {file_path} nicht gefunden.")
        return None, []

    with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
        in_qso_section = False
        for line in f:
            line = line.strip()
            # Leere Zeilen oder Kommentare überspringen
            if not line or line.startswith('#'):
                continue
                
            # Eigener Locator auslesen
            if line.upper().startswith("PWWLO="):
                my_locator = line.split('=', 1)[1].strip()
                continue
                
            # Erkennt '[QSORecords;XX]' flexibel per Teil-String
            if line.upper().startswith("[QSORECORDS"):
                in_qso_section = True
                continue
                
            # Wenn wir in der QSO-Sektion sind, Datenzeilen auswerten
            if in_qso_section:
                # Falls eine neue Sektion startet, QSO-Block beenden
                if line.startswith('['):
                    in_qso_section = False
                    continue
                    
                parts = line.split(';')
                # Mindestens 10 Felder erforderlich (Feld 10 = Index 9)
                if len(parts) >= 10:
                    call = parts[2].strip()  # Feld 3: Rufzeichen
                    locator = None
                    
                    # Direkt in Feld 10 prüfen (Index 9)
                    part_clean = parts[9].strip()  # Feld 10: Gegen-Locator
                    
                    # Validierung des empfangenen Maidenhead-Locators
                    if re.match(r'^[A-R]{2}[0-9]{2}[A-X]{2}$', part_clean, re.IGNORECASE) or \
                       re.match(r'^[A-R]{2}[0-9]{2}$', part_clean, re.IGNORECASE):
                        locator = part_clean.upper()

                    if call and locator:
                        qsos.append({'call': call, 'locator': locator})

    return my_locator, qsos

def generate_map(my_locator, qsos, file_path, output_html="qso_map.html"):
    """Erstellt die interaktive OpenStreetMap-Karte mit Entfernungskreisen und Log-Titel."""
    if not my_locator:
        home_coords = (51.0, 10.0)
    else:
        home_coords = locator_to_latlon(my_locator) or (51.0, 10.0)

    m = folium.Map(location=home_coords, zoom_start=6, tiles="CartoDB Positron")

    # Extrahiert den reinen Dateinamen aus dem Pfad
    log_name = os.path.basename(file_path)

    # Titel als HTML-Box oben mittig hinzufügen
    title_html = f'''
        <div style="
            position: fixed; 
            top: 20px; left: 50%; transform: translateX(-50%);
            z-index:9999; 
            background-color: rgba(255, 255, 255, 0.85);
            padding: 10px 20px; 
            border: 2px solid #3388ff; 
            border-radius: 8px;
            font-family: 'Helvetica Neue', Arial, sans-serif;
            font-size: 16px; 
            font-weight: bold;
            color: #333333;
            box-shadow: 0px 2px 5px rgba(0,0,0,0.2);
            pointer-events: none;
        ">
            Log: {log_name} ({len(qsos)} QSOs)
        </div>
    '''
    m.get_root().html.add_child(folium.Element(title_html))

    # Entfernungskreise von 100km bis 1000km zeichnen
    for radius_km in range(100, 1100, 100):
        folium.Circle(
            location=home_coords,
            radius=radius_km * 1000,
            color="blue",
            weight=1,
            fill=False,
            opacity=0.3,
            dash_array="5, 5",
            popup=f"{radius_km} km"
        ).add_to(m)

    # Heimat-Standort markieren
    if my_locator:
        folium.Marker(
            location=home_coords,
            popup=f"Home: {my_locator}",
            icon=folium.Icon(color='blue', icon='home')
        ).add_to(m)

    # Gegenstationen und Verbindungslinien eintragen
    for qso in qsos:
        target_coords = locator_to_latlon(qso['locator'])
        if target_coords:
            folium.Marker(
                location=target_coords,
                popup=f"{qso['call']} ({qso['locator']})",
                icon=folium.Icon(color='red', icon='info-sign')
            ).add_to(m)

            folium.PolyLine(
                locations=[home_coords, target_coords],
                color='darkred',
                weight=2,
                opacity=0.6
            ).add_to(m)

    m.save(output_html)
    print(f"HTML-Karte gespeichert unter: {output_html}")
    return output_html

def save_map_as_jpeg(html_path, output_jpeg):
    """Öffnet die HTML-Karte headless in Selenium und exportiert ein JPEG-Bild."""
    print("Starte Browser im Hintergrund für den Bild-Export...")
    
    options = Options()
    options.add_argument("--headless")
    
    # Performanz-Tweaks für die headless Sandbox
    options.set_preference("webgl.disabled", True)
    options.set_preference("layers.acceleration.disabled", True)
    options.set_preference("gfx.webrender.software", True)
    
    # Ubuntu Snap Container-Fix für Geckodriver
    snap_service = FirefoxService(executable_path='/snap/bin/geckodriver')
    
    driver = webdriver.Firefox(service=snap_service, options=options) 
    driver.set_window_size(1920, 1080)
    
    abs_html_path = os.path.abspath(html_path)
    driver.get(f"file://{abs_html_path}")
    
    # 4 Sekunden warten, damit alle OpenStreetMap-Kacheln fertig rendern
    time.sleep(4)
    
    driver.save_screenshot(output_jpeg)
    driver.quit()
    
    print(f"Erfolg: Statische Karte als Bild gespeichert unter: {output_jpeg}")

if __name__ == "__main__":
    # Parameterprüfung
    if len(sys.argv) < 2:
        print("Fehler: Kein EDI-Logfile angegeben.")
        print("Nutzung: python3 generate_map.py <pfad_zur_datei.edi>")
        sys.exit(1)

    edi_file_path = sys.argv[1]

    if not os.path.exists(edi_file_path):
        print(f"Fehler: Die Datei '{edi_file_path}' existiert nicht.")
        sys.exit(1)

    print(f"Verarbeite Logdatei: {edi_file_path}")
    my_loc, qso_list = parse_edi_file(edi_file_path)
    
    if qso_list:
        # Dynamische Namen basierend auf dem Log-Namen erzeugen
        base_name, _ = os.path.splitext(edi_file_path)
        html_file = f"{base_name}.html"
        jpeg_file = f"{base_name}.jpg"

        # 1. HTML Karte generieren
        generate_map(my_loc, qso_list, edi_file_path, output_html=html_file)
        
        # 2. HTML in JPEG konvertieren
        save_map_as_jpeg(html_file, output_jpeg=jpeg_file)
    else:
        print("Keine gültigen QSOs in der Datei gefunden. Bitte prüfe das EDI-Format.")

