import sys
import os
import subprocess
import tempfile
import re
import srt
import folium
import vlc
from math import radians, sin, cos, sqrt, atan2
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout,
    QWidget, QFileDialog, QHBoxLayout, QSlider, QSizePolicy, QFrame
)
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QFont
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings

def haversine(lat1, lon1, lat2, lon2):
    R = 6371.0
    lat1_rad = radians(lat1)
    lon1_rad = radians(lon1)
    lat2_rad = radians(lat2)
    lon2_rad = radians(lon2)
    dlon = lon2_rad - lon1_rad
    dlat = lat2_rad - lat1_rad
    a = sin(dlat / 2)**2 + cos(lat1_rad) * cos(lat2_rad) * sin(dlon / 2)**2
    c = 2 * atan2(sqrt(a), sqrt(1 - a))
    distance = R * c
    return distance

def extract_srt_from_mp4(mp4_path):
    temp_srt = tempfile.NamedTemporaryFile(suffix=".srt", delete=False)
    temp_srt.close()
    cmd = [
        "ffmpeg", "-y", "-i", mp4_path, "-map", "0:s:0", "-c:s", "srt", temp_srt.name
    ]
    try:
        subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        return temp_srt.name
    except subprocess.CalledProcessError:
        os.unlink(temp_srt.name)
        return None

def parse_telemetry_srt(srt_path):
    with open(srt_path, encoding="utf-8") as f:
        srt_content = f.read()
    subs = list(srt.parse(srt_content))
    telemetry = []
    for sub in subs:
        data = {
            "start": sub.start.total_seconds(),
            "end": sub.end.total_seconds(),
        }
        text = sub.content.replace('\n', ' ')
        m = re.search(r'GPS \(([-\d.]+),\s*([-\d.]+),\s*(\d+)\)', text)
        if m:
            data["lat"] = float(m.group(2))
            data["lon"] = float(m.group(1))
        m = re.search(r'H\s*([-\d.]+)m', text)
        if m:
            data["height"] = float(m.group(1))
        m = re.search(r'H\.S\s*([-\d.]+)m/s', text)
        if m:
            data["h_speed"] = float(m.group(1))
        telemetry.append(data)
    return telemetry

class MapWidget(QWebEngineView):
    def __init__(self, lat, lon):
        super().__init__()
        self.map = folium.Map(location=[lat, lon], zoom_start=16)
        
        self.start_marker = folium.Marker([lat, lon], popup="Start", icon=folium.Icon(color='green'))
        self.start_marker.add_to(self.map)
        
        self.current_marker = folium.Marker([lat, lon], icon=folium.Icon(color='red'))
        self.current_marker.add_to(self.map)
        
        self.path_line = folium.PolyLine([[lat, lon]], color="blue", weight=3, opacity=0.8)
        self.path_line.add_to(self.map)
        
        self.map_name = self.map.get_name()
        self.marker_name = self.current_marker.get_name()
        self.line_name = self.path_line.get_name()
        
        html_content = self.map.get_root().render()
        self.setHtml(html_content)

    def update_marker(self, lat, lon):
        js_code = f"""
            var new_latlng = L.latLng({lat}, {lon});
            {self.marker_name}.setLatLng(new_latlng);
            {self.line_name}.addLatLng(new_latlng);
            {self.map_name}.panTo(new_latlng);
        """
        self.page().runJavaScript(js_code)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("DJI Drone Telemetry Viewer")
        self.setGeometry(100, 100, 1280, 720)
        self.setStyleSheet("""
            QMainWindow { background-color: #23272b; }
            QLabel { color: #fff; }
            QPushButton { background: #3c4148; border: 1px solid #555; padding: 8px 16px; border-radius: 4px; color: white; }
            QPushButton:hover { background: #4a5058; }
            QPushButton:pressed { background: #2c3138; }
            QSlider::groove:horizontal { height: 8px; background: #333; border-radius: 4px; }
            QSlider::handle:horizontal { background: #4f8dcb; width: 16px; margin: -4px 0; border-radius: 8px; }
            QFrame { background: #111; }
        """)
        
        self.video_frame = QFrame()
        self.video_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.video_frame.setStyleSheet("background: #111; border-radius: 8px;")
        
        right_panel = QVBoxLayout()
        self.map_placeholder = QLabel("Karte wird geladen...")
        self.map_placeholder.setAlignment(Qt.AlignCenter)
        self.map_placeholder.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.map_placeholder.setStyleSheet("background: #222; border-radius: 8px; color: #888;")
        self.map_widget = None
        right_panel.addWidget(self.map_placeholder, stretch=3)
        
        self.gps_label = QLabel("<b>GPS</b><br>--")
        self.alt_label = QLabel("<b>Höhe</b><br>--")
        self.speed_label = QLabel("<b>Geschw.</b><br>--")
        self.dist_label = QLabel("<b>Distanz</b><br>--")
        hud_font = QFont("Arial", 11)
        for label in [self.gps_label, self.alt_label, self.speed_label, self.dist_label]:
            label.setFont(hud_font)
            label.setStyleSheet("margin-top: 10px; color: #fff;")
            right_panel.addWidget(label)
        right_panel.addStretch(1)

        self.play_btn = QPushButton("▶ Play")
        self.pause_btn = QPushButton("⏸ Pause")
        self.unload_btn = QPushButton("Unload")
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, 1000)
        self.time_label = QLabel("00:00 / 00:00")
        self.open_btn = QPushButton("Öffnen")
        
        main_layout = QHBoxLayout()
        main_layout.addWidget(self.video_frame, 3)
        right_panel_widget = QWidget()
        right_panel_widget.setLayout(right_panel)
        right_panel_widget.setMinimumWidth(280)
        right_panel_widget.setMaximumWidth(400)
        right_panel_widget.setStyleSheet("background: #181b1f; border-radius: 10px; padding: 10px;")
        main_layout.addWidget(right_panel_widget, 1)

        player_layout = QHBoxLayout()
        player_layout.addWidget(self.play_btn)
        player_layout.addWidget(self.pause_btn)
        player_layout.addWidget(self.slider)
        player_layout.addWidget(self.time_label)
        player_layout.addWidget(self.open_btn)
        player_layout.addWidget(self.unload_btn)
        
        vbox = QVBoxLayout()
        vbox.addLayout(main_layout)
        vbox.addLayout(player_layout)
        
        container = QWidget()
        container.setLayout(vbox)
        self.setCentralWidget(container)
        
        self.video_path = None
        self.telemetry = []
        self.start_coords = None
        self.telemetry_idx = 0
        self.slider_is_pressed = False

        self.vlc_instance = vlc.Instance("--no-xlib")
        self.media_player = self.vlc_instance.media_player_new()
        
        self.telemetry_timer = QTimer(self)
        self.telemetry_timer.setInterval(33)
        self.telemetry_timer.timeout.connect(self.update_telemetry_and_progress)

        self.open_btn.clicked.connect(self.open_video)
        self.play_btn.clicked.connect(self.play_video)
        self.pause_btn.clicked.connect(self.pause_video)
        self.unload_btn.clicked.connect(self.unload_video)
        self.slider.sliderPressed.connect(self.slider_pressed)
        self.slider.sliderReleased.connect(self.slider_released)

        self.play_btn.setEnabled(False)
        self.pause_btn.setEnabled(False)
        self.unload_btn.setEnabled(False)
        self.slider.setEnabled(False)

    def open_video(self):
        fname, _ = QFileDialog.getOpenFileName(self, "Video auswählen", "", "MP4 Files (*.mp4)")
        if not fname:
            return
            
        self.unload_video()

        self.video_path = fname
        srt_path = extract_srt_from_mp4(fname)
        if not srt_path or not os.path.exists(srt_path):
            self.gps_label.setText("Keine Telemetriedaten (SRT) gefunden.")
            return
        
        self.telemetry = parse_telemetry_srt(srt_path)
        os.unlink(srt_path)
        
        if not self.telemetry or "lat" not in self.telemetry[0]:
            self.gps_label.setText("Keine GPS-Daten in der Telemetrie.")
            return

        self.start_coords = (self.telemetry[0]["lat"], self.telemetry[0]["lon"])
        
        if self.map_widget:
            self.map_widget.deleteLater()
        self.map_widget = MapWidget(self.start_coords[0], self.start_coords[1])
        
        right_layout = self.centralWidget().layout().itemAt(0).layout().itemAt(1).widget().layout()
        right_layout.replaceWidget(self.map_placeholder, self.map_widget)
        self.map_placeholder.hide()
        self.map_widget.show()
        
        media = self.vlc_instance.media_new(self.video_path)
        self.media_player.set_media(media)
        self.media_player.set_hwnd(self.video_frame.winId())
        
        self.play_btn.setEnabled(True)
        self.pause_btn.setEnabled(True)
        self.unload_btn.setEnabled(True)
        self.slider.setEnabled(True)
        self.play_video()

    def play_video(self):
        if self.media_player.get_media():
            self.media_player.play()
            self.telemetry_timer.start()
            self.play_btn.setEnabled(False)
            self.pause_btn.setEnabled(True)

    def pause_video(self):
        if self.media_player.is_playing():
            self.media_player.pause()
            self.telemetry_timer.stop()
            self.play_btn.setEnabled(True)
            self.pause_btn.setEnabled(False)

    def unload_video(self):
        self.media_player.stop()
        self.telemetry_timer.stop()
        
        self.video_path = None
        self.telemetry = []
        self.start_coords = None
        self.telemetry_idx = 0
        
        if self.map_widget:
            self.map_widget.hide()
            right_layout = self.centralWidget().layout().itemAt(0).layout().itemAt(1).widget().layout()
            right_layout.replaceWidget(self.map_widget, self.map_placeholder)
            self.map_widget.deleteLater()
            self.map_widget = None
            self.map_placeholder.show()
            
        self.gps_label.setText("<b>GPS</b><br>--")
        self.alt_label.setText("<b>Höhe</b><br>--")
        self.speed_label.setText("<b>Geschw.</b><br>--")
        self.dist_label.setText("<b>Distanz</b><br>--")
        self.time_label.setText("00:00 / 00:00")
        self.slider.setValue(0)
        
        self.play_btn.setEnabled(False)
        self.pause_btn.setEnabled(False)
        self.unload_btn.setEnabled(False)
        self.slider.setEnabled(False)

    def update_telemetry_and_progress(self):
        duration_ms = self.media_player.get_length()
        pos_ms = self.media_player.get_time()
        
        if duration_ms <= 0:
            return
            
        pos_sec = pos_ms / 1000.0
        
        if not self.slider_is_pressed:
            self.slider.setValue(int((pos_ms / duration_ms) * 1000))
        self.time_label.setText(f"{self.format_time(pos_sec)} / {self.format_time(duration_ms / 1000.0)}")
        
        while (self.telemetry_idx + 1 < len(self.telemetry) and
               self.telemetry[self.telemetry_idx + 1]["start"] <= pos_sec):
            self.telemetry_idx += 1
        
        data = self.telemetry[self.telemetry_idx] if self.telemetry_idx < len(self.telemetry) else {}
        self.update_hud(data)
        
        lat = data.get("lat")
        lon = data.get("lon")
        if lat is not None and lon is not None and self.map_widget:
            self.map_widget.update_marker(lat, lon)
            
        if self.media_player.get_state() == vlc.State.Ended:
            self.video_finished()

    def update_hud(self, data):
        lat = data.get('lat')
        lon = data.get('lon')
        alt = data.get('height', '--')
        speed_ms = data.get('h_speed', 0.0)
        
        if lat is not None and lon is not None:
            self.gps_label.setText(f"<b>GPS</b><br>{lat:.5f}°, {lon:.5f}°")
            if self.start_coords:
                dist_km = haversine(self.start_coords[0], self.start_coords[1], lat, lon)
                self.dist_label.setText(f"<b>Distanz</b><br>{dist_km*1000:.1f} m")
        
        if isinstance(alt, float):
            self.alt_label.setText(f"<b>Höhe</b><br>{alt:.1f} m")

        speed_kmh = speed_ms * 3.6
        self.speed_label.setText(f"<b>Geschw.</b><br>{speed_kmh:.1f} km/h")
        
    def slider_pressed(self):
        if self.media_player.is_playing():
            self.slider_is_pressed = True
            self.media_player.pause()
            self.telemetry_timer.stop()

    def slider_released(self):
        if self.slider_is_pressed:
            seek_ratio = self.slider.value() / 1000.0
            self.media_player.set_position(seek_ratio)
            
            new_time_sec = (self.media_player.get_length() / 1000.0) * seek_ratio
            self.telemetry_idx = 0
            while (self.telemetry_idx + 1 < len(self.telemetry) and
                   self.telemetry[self.telemetry_idx + 1]["start"] <= new_time_sec):
                self.telemetry_idx += 1
            
            self.media_player.play()
            self.telemetry_timer.start()
        self.slider_is_pressed = False
        self.play_btn.setEnabled(False)
        self.pause_btn.setEnabled(True)

    def video_finished(self):
        self.telemetry_timer.stop()
        self.play_btn.setEnabled(True)
        self.pause_btn.setEnabled(False)
        self.slider.setValue(1000)

    def format_time(self, sec):
        return f"{int(sec)//60:02}:{int(sec)%60:02}"
        
    def closeEvent(self, event):
        self.media_player.stop()
        self.media_player.release()
        event.accept()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    
    try:
        QWebEngineSettings.globalSettings().setAttribute(QWebEngineSettings.WebAttribute.WebGLEnabled, False)
    except Exception:
        pass

    window = MainWindow()
    window.show()
    sys.exit(app.exec_())