from qgis.PyQt.QtWidgets import QDockWidget, QVBoxLayout, QTextBrowser, QWidget, QMessageBox, QFileDialog
from qgis.PyQt.QtCore import Qt, QTimer
from qgis.PyQt.QtGui import QColor, QDesktopServices
from qgis.core import Qgis, QgsProject, QgsRasterLayer
from qgis.gui import QgsHighlight
from ..utils.identify_tool import IdentifyMapTool
from ..utils.api import APIGetPlanRefUrl
import tempfile
import requests
import os


class LayerDetailsDock(QDockWidget):
    def __init__(self, iface, cognito_session):
        super().__init__("XPlanung24 - Ebenen Details", iface.mainWindow())
        self.iface = iface
        self.cognito = cognito_session
        self.map_tool = None
        self.api_response = None
        self._identify_results = []
        self._highlights = []
        self._document_urls = {}  # Speichert URL-Mapping für Dokument-Actions
        self._plan_id = None  # Aktuelle Plan-ID für Dokument-Downloads
        self._plan_path = None  # Aktueller Plan-Pfad für Dokument-Downloads
        self._refs = []  # Verfügbare Dateien für Download

        self.setup_ui()
        self.setup_map_tool()

    def setup_ui(self):
        # Container Widget
        widget = QWidget()
        layout = QVBoxLayout()

        # === Styles ===
        self.setStyleSheet("""
            QWidget { background-color: #eee; padding:2px; border:0; }
            QTextBrowser { background-color: #fff; padding:12px; }

            /* === Scrollbar styling === */
            QScrollBar:vertical {
                border: none;
                background: #fff;
                width: 8px;
                margin: 0px 0px 0px 0px;
            }

            QScrollBar::handle:vertical {
                background: #000;
                min-height: 35px;
                border-radius: 4px;
            }

            QScrollBar::handle:vertical:hover {
                background: #888;
            }

            QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
                height: 0px;  /* hide arrows */
            }

            QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
                background: none;
            }

            QScrollBar:horizontal {
                border: none;
                background: #f0f0f0;
                height: 10px;
                margin: 0px 0px 0px 0px;
            }

            QScrollBar::handle:horizontal {
                background: #b0b0b0;
                min-width: 20px;
                border-radius: 4px;
            }

            QScrollBar::handle:horizontal:hover {
                background: #888;
            }

            QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {
                width: 0px;
            }

            QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
                background: none;
            }
        """)

        # HTML/Text Browser für die Anzeige
        self.text_browser = QTextBrowser()
        self.text_browser.setOpenExternalLinks(False)
        self.text_browser.setOpenLinks(False)  # Keine automatische Navigation – alles über anchorClicked
        self.text_browser.anchorClicked.connect(self.on_anchor_clicked)
        self.text_browser.setHtml("""
            <h3>XPLAN Flächeninhalte anzeigen</h3>
            <p>
              Klicken Sie auf eine Fläche in Ihrem Plan, um alle zugehörigen XPlan-Informationen der Fläche anzuzeigen.
              <br><br>
              <strong>Hinweis:</strong> XPLANUNG24 übernimmt automatisch die Übersetzung sämtlicher XPlan-Objekte, Codes und Bezeichnungen in ein lesbares, verständliches Format – damit Sie die Inhalte Ihres Plans einfach nachvollziehen können.
            </p>
        """)
        layout.addWidget(self.text_browser)

        widget.setLayout(layout)
        self.setWidget(widget)

    def setup_map_tool(self):
        """Richtet das Map-Tool für Feature-Identifikation ein"""
        self.map_tool = IdentifyMapTool(self.iface, radius=5)
        self.map_tool.featureIdentified.connect(self.handle_feature_identified)
        self.iface.mapCanvas().setMapTool(self.map_tool)

        self.iface.messageBar().pushMessage(
            "XPlanung24",
            "Klicken Sie auf die Karte, um Ebenen-Details abzurufen.",
            level=Qgis.Info,
            duration=4
        )

    def handle_feature_identified(self, results):
        """Verarbeitet identifizierte Features und ruft die Details aus Layer Properties ab"""
        if not results:
            self.iface.messageBar().pushMessage(
                "XPlanung24",
                "Keine Features in der Nähe gefunden.",
                level=Qgis.Warning,
                duration=3,
            )
            return

        # Sammle alle GML-IDs und hole Details vom ANGEKLICKTEN Layer
        gml_ids = []
        details_data = None
        self._identify_results = results

        for layer_name_or_obj, gml_id in results:
            if gml_id:
                gml_ids.append(gml_id)

            layer = None
            if isinstance(layer_name_or_obj, str):
                for proj_layer in QgsProject.instance().mapLayers().values():
                    if proj_layer.name() == layer_name_or_obj:
                        layer = proj_layer
                        break
            else:
                layer = layer_name_or_obj

            # Hole Details, planId und planPath aus Layer Custom Property
            if layer is not None and details_data is None:
                try:
                    import json
                    details_json = layer.customProperty("xplanung24_details")
                    if details_json:
                        details_data = json.loads(details_json)

                    # Plan-ID und Plan-Pfad für Dokument-Downloads
                    self._plan_id = layer.customProperty("xplanung24_plan_id")
                    self._plan_path = layer.customProperty("xplanung24_plan_path")

                    # Verfügbare Refs für Download-Prüfung
                    refs_json = layer.customProperty("xplanung24_refs")
                    if refs_json:
                        self._refs = json.loads(refs_json)
                    else:
                        self._refs = []
                except Exception:
                    pass

        if not gml_ids:
            self.iface.messageBar().pushMessage(
                "XPlanung24",
                "Keine gültigen GML-IDs gefunden.",
                level=Qgis.Warning,
                duration=3,
            )
            return
        
        if not details_data:
            self.iface.messageBar().pushMessage(
                "XPlanung24",
                "Keine Details für diesen Plan gefunden.",
                level=Qgis.Warning,
                duration=3,
            )
            return

        # 🔑 Filtere Details nach GML-IDs
        filtered_details = []
        for section in details_data:
            if isinstance(section, dict) and 'details' in section:
                # Filtere Details die zu unseren gmlIds gehören
                matching_details = []
                matched_gml_ids = []
                for detail_group in section.get('details', []):
                    if isinstance(detail_group, dict) and 'gmlId' in detail_group:
                        if detail_group['gmlId'] in gml_ids:
                            matching_details.append(detail_group.get('details', []))
                            matched_gml_ids.append(detail_group['gmlId'])

                # Flatten und Section hinzufügen
                if matching_details:
                    flattened = []
                    for detail_list in matching_details:
                        if isinstance(detail_list, list):
                            flattened.extend(detail_list)

                    if flattened:
                        filtered_details.append({
                            'name': section.get('name', 'Unbenannt'),
                            'details': flattened,
                            '_gml_ids': matched_gml_ids,
                        })

        # Speichere gefilterte Response für Navigation
        self.api_response = filtered_details
        
        # Zeige Inhaltsverzeichnis
        self.show_table_of_contents()

        self.iface.messageBar().pushMessage(
            "XPlanung24",
            f"Details für {len(gml_ids)} Feature(s) geladen.",
            level=Qgis.Info,
            duration=4,
        )
    
    def show_table_of_contents(self):
        """Zeigt das Inhaltsverzeichnis aller Sections"""
        html = """
        <style>
            body {
                font-family: Arial, sans-serif;
                background-color: #fafafa;
                padding: 10px 14px;
            }
 
            .title {
                padding-top:6px;
                padding-left:6px;
            }   
            
            .title h2{
                font-size:28px;
                font-weight:500;
            }
            
            .toc-block {
                margin-top:12px;
            }    
                 
            .toc-item {
                border-top:1px solid #eee;
                padding:12px;
            }
            .toc-item a {
                padding:12px;
                font-size:16px;
                color:#000;
                text-decoration:none;
            }
            .flash-btn {
                color: #2563eb;
                font-size: 18px;
                text-decoration: none;
                padding: 2px 6px;
                margin-right: 8px;
                vertical-align: middle;
            }
        </style>
        """

        html += "<div class='title'>"
        html += "<h2>Ebene wählen</h2>"
        html += "</div>"

        if isinstance(self.api_response, list):
            html += "<table class='toc-block'>"
            for idx, section in enumerate(self.api_response):
                if isinstance(section, dict) and 'name' in section:
                    section_name = section.get('name', 'Unbenannt')
                    has_gml = bool(section.get('_gml_ids'))
                    html += "<tr>"
                    if has_gml:
                        html += f"<td style='padding:12px 8px 12px 12px; border-top:1px solid #eee; width:24px;'>"
                        html += f"<a href='flash:{idx}' class='flash-btn' title='Auf Karte hervorheben'>&#9678;</a>"
                        html += "</td>"
                    html += f"<td class='toc-item'>"
                    html += f"<a href='section:{idx}' class='toc-link'>{section_name}</a>"
                    html += "</td>"
                    html += "</tr>"
            html += "</table>"
        self.text_browser.setHtml(html)
    
    def show_section(self, section_idx):
        """Zeigt eine einzelne Section mit Details"""
        if not isinstance(self.api_response, list) or section_idx >= len(self.api_response):
            return
        
        section = self.api_response[section_idx]
        section_name = section.get('name', 'Unbenannt')
        
        html = """
        <style>
            body {
                font-family: Arial, sans-serif;
                background-color: #fafafa;
                padding: 10px 14px;
            }
            h2 {
                color: #1a1a1a;
                font-size: 20px;
                margin-bottom: 15px;
                font-weight: bold;
            }
            .top-bar {
                display:block;
                padding: 4px 4px 8px 4px ;
            }
            
            .top-bar a{
                font-size:20px;
                color:#000;
                text-decoration:none;
            }
            
            .title {
                padding-top:6px;
                padding-left:6px;
            }   
            
            .title h2{
                font-size:28px;
                font-weight:500;
            }
            .detail-item {
                padding-top:18px;
                display:block;
                margin-top:18px;
            }
            
            .detail-value {
                font-size:12px;
                font-weight:200;
                color:#666;
            }
            
            .detail-name {
                font-size:12px;
                font-weight:500;
                color: #011627 !important;
                padding-top:6px
            }
            
            .detail-block {
                font-size:12px;
                font-weight:300;
                color:#666;
                padding-top:6px;
            }
            
            .detail-blockname {
                font-size:12px;
                margin-top:6px;
                font-weight:500;
                color: #666 !important;
                padding-right:12px;
                padding-bottom:4px;
                width:250px;
            }
            
            .detail-item {
                padding:6px;
                border-left:4px solid #eee;
            }
            .details-table {
                margin-top:12px;
            }
        </style>
        """

        html += "<table class='top-bar'>"
        html += "<tr>"
        html += "<td>"
        html += "<a href='toc' class='back-button'>←</a>"
        html += "</td>"
        html += "<td class='title'>"
        html += f"<h2>{section_name}</h2>"
        html += "</td>"
        html += "</tr>"
        html += "</table>"
        
        details = section.get('details', [])
        if details:
            old_name = ""
        
            for detail in details:
                if isinstance(detail, dict):
                    detail_name = detail.get('name', '')
                    detail_type = detail.get('type', '')
                    detail_values = detail.get('values', '')
                    
                    # Spezielle Behandlung für Text-Abschnitt
                    if detail_name == 'Text-Abschnitt' and detail_type == 'json' and isinstance(detail_values, list):
                        
                        if old_name != detail_name and detail_name == 'Text-Abschnitt': 
                            html += "<div class='detail-item'>"
                            html += "<div class='detail-name'>Text-Abschnitt:</div>"
                            html += "</div>"
                            old_name = detail_name

                        html += "<table class='details-table'>"
                        html += "<tr>"
                        html += "<td class='detail-item'>"
                        
                        for item in detail_values:
                            if isinstance(item, dict):
                                label = item.get('label', '')
                                value = item.get('value', '')
                                
                                if label and value:
                                    formatted_value = str(value).replace('\\r\\n', '<br>').replace('\r\n', '<br>').replace('\n', '<br>')
                                    html += f"<div class='detail-blockname'>{label}:</div>"
                                    html += f"<div class='detail-block'>{formatted_value}</div>"
                            elif isinstance(item, str):
                                try:
                                    import ast
                                    parsed = ast.literal_eval(item)
                                    if isinstance(parsed, dict):
                                        label = parsed.get('label', '')
                                        value = parsed.get('value', '')
                                        
                                        if label and value:
                                            formatted_value = str(value).replace('\\r\\n', '<br>').replace('\r\n', '<br>').replace('\n', '<br>')
                                            html += f"<div class='detail-blockname'>{label}:</div>"
                                            html += f"<div class='detail-block'>{formatted_value}</div>"
                                except:
                                    html += f"<div class='detail-value'>{item}</div>"
                        
                        html += "</td>"
                        html += "</tr>"
                        html += "</table>"
                    
                    else:
                        html += "<div class='detail-item'>"
                        html += f"<div class='detail-name'>{detail_name}:</div> "

                        if detail_type == 'document' and isinstance(detail_values, list):
                            html += "<table style='margin-top:8px; margin-left:20px;'>"
                            for doc_idx, doc in enumerate(detail_values):
                                if isinstance(doc, dict):
                                    # XPlan-Felder mit xplan:-Präfix
                                    doc_name = doc.get('xplan:referenzName', doc.get('name', 'Dokument'))
                                    doc_url = doc.get('xplan:referenzURL', doc.get('url', ''))
                                    doc_georef_url = doc.get('xplan:georefURL', '')
                                    doc_art = doc.get('xplan:art', '')
                                    doc_mime = doc.get('mimeType', '').lower()

                                    # Speichere URL für späteren Zugriff
                                    doc_key = f"doc_{section_idx}_{doc_idx}"
                                    self._document_urls[doc_key] = {
                                        'url': doc_url,
                                        'name': doc_name,
                                        'mimeType': doc_mime
                                    }
                                    # Separate Geo-Datei URL speichern falls vorhanden
                                    if doc_georef_url:
                                        georef_key = f"georef_{section_idx}_{doc_idx}"
                                        self._document_urls[georef_key] = {
                                            'url': doc_georef_url,
                                            'name': f"Geo_{doc_name}" if doc_name else 'Geo-Datei',
                                            'mimeType': ''
                                        }

                                    # Dateiendung aus Name oder URL extrahieren
                                    name_lower = doc_name.lower()
                                    url_lower = doc_url.lower() if doc_url else ''

                                    # Dateityp ermitteln
                                    is_geotiff = False
                                    file_type = ''

                                    if 'pdf' in doc_mime or name_lower.endswith('.pdf') or url_lower.endswith('.pdf'):
                                        file_type = 'PDF'
                                    elif ('tiff' in doc_mime or 'tif' in doc_mime or 'geotiff' in doc_mime or
                                          name_lower.endswith(('.tif', '.tiff')) or
                                          url_lower.endswith(('.tif', '.tiff')) or
                                          '.tif?' in url_lower or '.tiff?' in url_lower):
                                        is_geotiff = True
                                        file_type = 'TIF'
                                    elif ('image' in doc_mime or
                                          name_lower.endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp')) or
                                          url_lower.endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))):
                                        # Extrahiere genaue Endung
                                        for ext in ['.png', '.jpg', '.jpeg', '.gif', '.bmp']:
                                            if name_lower.endswith(ext) or url_lower.endswith(ext):
                                                file_type = ext[1:].upper()
                                                break
                                        if not file_type:
                                            file_type = 'Bild'
                                    elif name_lower.endswith('.gml') or url_lower.endswith('.gml') or 'gml' in doc_mime:
                                        file_type = 'GML'
                                    elif name_lower.endswith('.zip') or url_lower.endswith('.zip') or 'zip' in doc_mime:
                                        file_type = 'ZIP'
                                    else:
                                        # Versuche Endung aus Name zu extrahieren
                                        if '.' in doc_name:
                                            file_type = doc_name.rsplit('.', 1)[-1].upper()

                                    if doc_url:
                                        is_external_url = doc_url.startswith('http://') or doc_url.startswith('https://')
                                        # Prüfe ob Datei in refs verfügbar ist (nur für relative URLs)
                                        is_available = is_external_url or (doc_url in self._refs)

                                        # Dokument als Tabellenzeile
                                        html += "<tr><td style='padding:10px 0 16px 0; border-bottom:1px solid #eee;'>"

                                        # Dateiname und Typ
                                        html += f"<div style='font-size:13px; margin-bottom:10px;'>{doc_name}"
                                        if file_type:
                                            html += f" <span style='color:#888; font-size:11px;'>({file_type})</span>"
                                        if doc_art:
                                            html += f" <span style='color:#888; font-size:11px;'>– {doc_art}</span>"
                                        html += "</div>"

                                        # Buttons nur anzeigen wenn Datei verfügbar
                                        if is_available:
                                            if is_external_url:
                                                html += f"<div style='margin-bottom:6px;'><a href='{doc_url}' style='color:#444; font-size:12px; text-decoration:none;'>↓ Download</a></div>"
                                            else:
                                                html += f"<div style='margin-bottom:6px;'><a href='download:{doc_key}' style='color:#444; font-size:12px; text-decoration:none;'>↓ Download</a></div>"
                                                if is_geotiff:
                                                    html += f"<div style='margin-bottom:6px;'><a href='loadraster:{doc_key}' style='color:#444; font-size:12px; text-decoration:none;'>◎ In QGIS laden</a></div>"

                                            # Geo-Datei als gleichwertiger Button
                                            if doc_georef_url:
                                                georef_key = f"georef_{section_idx}_{doc_idx}"
                                                is_georef_external = doc_georef_url.startswith('http://') or doc_georef_url.startswith('https://')
                                                is_georef_available = is_georef_external or (doc_georef_url in self._refs)
                                                if is_georef_available:
                                                    if is_georef_external:
                                                        html += f"<div style='margin-bottom:6px;'><a href='{doc_georef_url}' style='color:#444; font-size:12px; text-decoration:none;'>↓ Geo-Datei Download</a></div>"
                                                    else:
                                                        html += f"<div style='margin-bottom:6px;'><a href='download:{georef_key}' style='color:#444; font-size:12px; text-decoration:none;'>↓ Geo-Datei Download</a></div>"
                                                else:
                                                    html += f"<div style='margin-bottom:6px; color:#999; font-size:12px;'>Geo-Datei nicht verfügbar</div>"
                                        else:
                                            html += f"<div style='color:#999; font-size:12px;'>Datei nicht verfügbar</div>"

                                        html += "</td></tr>"
                                    else:
                                        html += f"<tr><td style='padding:10px 0 16px 0; border-bottom:1px solid #eee; color:#999;'>"
                                        html += f"{doc_name} (keine URL)"
                                        html += "</td></tr>"
                                else:
                                    html += f"<tr><td style='padding:10px 0 12px;'>{doc}</td></tr>"
                            html += "</table>"
                        
                        elif detail_type == 'json' and isinstance(detail_values, list):
                            html += "<ul style='color:#666'>"
                            for item in detail_values:
                                html += f"<li>{item}</li>"
                            html += "</ul>"
                        
                        elif isinstance(detail_values, list):
                            html += "<ul>"
                            for val in detail_values:
                                html += f"<li>{val}</li>"
                            html += "</ul>"
                        
                        elif isinstance(detail_values, str):
                            formatted_value = detail_values.replace('\n', '<br>')
                            html += f"<div class='detail-value'>{formatted_value}</div>"
                        
                        else:
                            html += f"<div class='detail-value'>{detail_values}</div>"
                        
                        html += "</div>"
        else:
            html += "<p><i>Keine Details verfügbar</i></p>"
        
        self.text_browser.setHtml(html)
    
    def on_anchor_clicked(self, url):
        """Handler für Link-Klicks"""
        url_str = url.toString()

        if url_str == 'toc':
            # Zurück zum Inhaltsverzeichnis
            self.show_table_of_contents()
        elif url_str.startswith('flash:'):
            try:
                section_idx = int(url_str.split(':')[1])
                self._flash_section_features(section_idx)
            except Exception:
                pass
        elif url_str.startswith('section:'):
            # Zeige Section
            try:
                section_idx = int(url_str.split(':')[1])
                self.show_section(section_idx)
            except Exception:
                pass
        elif url_str.startswith('download:'):
            # Download-Button geklickt
            doc_key = url_str.split(':', 1)[1]
            self._download_document(doc_key)
        elif url_str.startswith('loadraster:'):
            # GeoTIFF in QGIS laden
            doc_key = url_str.split(':', 1)[1]
            self._load_raster_in_qgis(doc_key)
        elif url_str.startswith('http://') or url_str.startswith('https://') or url_str.startswith('file://'):
            # Externe Links im Browser öffnen
            QDesktopServices.openUrl(url)
        else:
            # Versuche als URL zu öffnen (für relative oder andere Links)
            QDesktopServices.openUrl(url)
    
    def _flash_section_features(self, section_idx):
        """Lässt die Features einer Section kurz auf der Karte aufleuchten."""
        self._clear_highlights()

        if not isinstance(self.api_response, list) or section_idx >= len(self.api_response):
            return

        section = self.api_response[section_idx]
        section_gml_ids = set(section.get('_gml_ids', []))

        if not section_gml_ids:
            return

        canvas = self.iface.mapCanvas()

        # GML-ID → Layer-Name Mapping aus den Identify-Ergebnissen
        gml_to_layer_name = {}
        for layer_name, gml_id in self._identify_results:
            if gml_id:
                gml_to_layer_name[gml_id] = layer_name

        # Layer-Name → Layer-Objekt auflösen
        layers_by_name = {}
        for proj_layer in QgsProject.instance().mapLayers().values():
            layers_by_name[proj_layer.name()] = proj_layer

        # Features finden und highlighten
        for gml_id in section_gml_ids:
            layer_name = gml_to_layer_name.get(gml_id)
            if not layer_name:
                continue
            layer = layers_by_name.get(layer_name)
            if not layer:
                continue

            # GML-ID-Feld ermitteln und Feature per Expression suchen
            gml_field = None
            for name in layer.fields().names():
                if name.lower() in ("gml_id", "gmlid", "_gml_id", "fid", "id"):
                    gml_field = name
                    break
            if not gml_field:
                continue

            for feat in layer.getFeatures(f"\"{gml_field}\" = '{gml_id}'"):
                h = QgsHighlight(canvas, feat, layer)
                h.setColor(QColor(255, 100, 0, 220))
                h.setFillColor(QColor(255, 100, 0, 80))
                h.setWidth(3)
                self._highlights.append(h)
                break

        if self._highlights:
            QTimer.singleShot(1800, self._clear_highlights)

    def _clear_highlights(self):
        """Entfernt alle aktiven Highlights von der Karte."""
        for h in self._highlights:
            h.hide()
        self._highlights = []

    def _move_point_layers_to_top(self, group):
        """Verschiebt alle Point-Layer (PPO) an die Spitze der Gruppe.

        PPO-Layer müssen immer über Raster- und Polygon-Layern sichtbar sein.
        """
        from qgis.core import QgsLayerTreeLayer, QgsVectorLayer

        # Sammle alle Point-Layer und deren aktuelle Positionen
        point_layers_info = []
        for i, node in enumerate(group.children()):
            if isinstance(node, QgsLayerTreeLayer):
                layer = node.layer()
                if layer and isinstance(layer, QgsVectorLayer):
                    # geometryType(): 0 = Point, 1 = Line, 2 = Polygon
                    if layer.geometryType() == 0:
                        point_layers_info.append({
                            'layer': layer,
                            'node': node,
                            'index': i
                        })

        if not point_layers_info:
            return

        # Verschiebe jeden Point-Layer an den Anfang (Index 0)
        # Rückwärts iterieren damit die Reihenfolge erhalten bleibt
        for info in reversed(point_layers_info):
            layer = info['layer']
            old_node = info['node']

            # Neuen Node erstellen und an Position 0 einfügen
            new_node = QgsLayerTreeLayer(layer)
            group.insertChildNode(0, new_node)

            # Alten Node entfernen (ist jetzt weiter unten weil wir oben eingefügt haben)
            group.removeChildNode(old_node)

    def _resolve_document_url(self, url, display_name):
        """Löst relative URLs auf (generiert presigned S3 URL wenn nötig)

        Args:
            url: Die URL oder der Dateiname aus dem GML (z.B. 'DE_03457014_O28_01_clip.tif')
            display_name: Der Anzeigename des Dokuments (für Fehlermeldungen)
        """
        # Prüfe ob es bereits eine vollständige URL ist
        if url and (url.startswith('http://') or url.startswith('https://')):
            return url

        # Relative URL - wir brauchen planId um eine Download-URL zu generieren
        if not self._plan_id:
            return None

        # Verwende die URL (den Dateinamen), nicht den Anzeigenamen
        filename = url if url else display_name

        try:
            download_url = APIGetPlanRefUrl(
                self.cognito,
                self._plan_id,
                filename,
                self._plan_path
            )
            if download_url:
                return download_url
        except Exception:
            pass

        return None

    def _download_document(self, doc_key):
        """Lädt ein Dokument herunter mit Speichern-unter-Dialog"""
        doc_info = self._document_urls.get(doc_key)
        if not doc_info or not doc_info.get('url'):
            self.iface.messageBar().pushMessage(
                "XPlanung24",
                "Dokument-URL nicht gefunden.",
                level=Qgis.Warning,
                duration=3
            )
            return

        url = doc_info['url']
        name = doc_info.get('name', 'dokument')

        # Resolve relative URLs
        download_url = self._resolve_document_url(url, name)
        if not download_url:
            self.iface.messageBar().pushMessage(
                "XPlanung24",
                f"Konnte Download-URL für '{name}' nicht generieren. Plan-ID fehlt.",
                level=Qgis.Warning,
                duration=5
            )
            return

        # Dateiendung ermitteln
        ext = ''
        if '.' in name:
            ext = name[name.rfind('.'):]
        elif '.' in url:
            # Versuche Endung aus URL zu extrahieren (vor ? für Query-Params)
            url_path = url.split('?')[0]
            if '.' in url_path:
                ext = url_path[url_path.rfind('.'):]

        # Filter für Speichern-Dialog
        filter_str = "Alle Dateien (*)"
        if ext.lower() in ['.pdf']:
            filter_str = "PDF-Dateien (*.pdf);;Alle Dateien (*)"
        elif ext.lower() in ['.tif', '.tiff']:
            filter_str = "GeoTIFF-Dateien (*.tif *.tiff);;Alle Dateien (*)"
        elif ext.lower() in ['.png', '.jpg', '.jpeg']:
            filter_str = "Bilder (*.png *.jpg *.jpeg);;Alle Dateien (*)"
        elif ext.lower() in ['.gml']:
            filter_str = "GML-Dateien (*.gml);;Alle Dateien (*)"
        elif ext.lower() in ['.zip']:
            filter_str = "ZIP-Archive (*.zip);;Alle Dateien (*)"

        # Speichern-unter-Dialog anzeigen
        save_path, _ = QFileDialog.getSaveFileName(
            self,
            f"Dokument speichern: {name}",
            name,  # Vorgeschlagener Dateiname
            filter_str
        )

        if not save_path:
            # Benutzer hat abgebrochen
            return

        self.iface.messageBar().pushMessage(
            "XPlanung24",
            f"Lade '{name}' herunter...",
            level=Qgis.Info,
            duration=2
        )

        try:
            # Datei herunterladen
            response = requests.get(download_url, timeout=120)
            response.raise_for_status()

            # Datei speichern
            with open(save_path, 'wb') as f:
                f.write(response.content)

            self.iface.messageBar().pushMessage(
                "XPlanung24",
                f"Gespeichert: {save_path}",
                level=Qgis.Success,
                duration=5
            )

        except requests.exceptions.RequestException as e:
            self.iface.messageBar().pushMessage(
                "XPlanung24",
                f"Download-Fehler: {str(e)}",
                level=Qgis.Critical,
                duration=5
            )
        except Exception as e:
            self.iface.messageBar().pushMessage(
                "XPlanung24",
                f"Fehler beim Speichern: {str(e)}",
                level=Qgis.Critical,
                duration=5
            )

    def _load_raster_in_qgis(self, doc_key):
        """Lädt ein GeoTIFF/Raster direkt in QGIS unter dem aktuellen Plan"""
        doc_info = self._document_urls.get(doc_key)
        if not doc_info or not doc_info.get('url'):
            self.iface.messageBar().pushMessage(
                "XPlanung24",
                "Dokument-URL nicht gefunden.",
                level=Qgis.Warning,
                duration=3
            )
            return

        url = doc_info['url']
        name = doc_info.get('name', 'Raster')

        # Resolve relative URLs
        download_url = self._resolve_document_url(url, name)
        if not download_url:
            self.iface.messageBar().pushMessage(
                "XPlanung24",
                f"Konnte Download-URL für '{name}' nicht generieren. Plan-ID fehlt.",
                level=Qgis.Warning,
                duration=5
            )
            return

        self.iface.messageBar().pushMessage(
            "XPlanung24",
            f"Lade Raster: {name}...",
            level=Qgis.Info,
            duration=2
        )

        try:
            # Lade Datei herunter
            response = requests.get(download_url, timeout=120)
            response.raise_for_status()

            # Speichere temporär
            suffix = '.tif'
            if name.lower().endswith('.tiff'):
                suffix = '.tiff'
            elif name.lower().endswith('.png'):
                suffix = '.png'
            elif name.lower().endswith('.jpg') or name.lower().endswith('.jpeg'):
                suffix = '.jpg'

            tmp_file = tempfile.NamedTemporaryFile(
                suffix=suffix,
                prefix="xplan_raster_",
                delete=False
            )
            tmp_file.write(response.content)
            tmp_file.flush()
            tmp_file.close()

            # Erstelle Raster-Layer
            layer_name = os.path.splitext(name)[0]
            raster_layer = QgsRasterLayer(tmp_file.name, layer_name)

            if not raster_layer.isValid():
                self.iface.messageBar().pushMessage(
                    "XPlanung24",
                    f"Fehler: Raster konnte nicht geladen werden.",
                    level=Qgis.Critical,
                    duration=5
                )
                return

            # Finde die Plan-Gruppe und füge den Layer UNTEN hinzu
            project = QgsProject.instance()
            root = project.layerTreeRoot()

            # Suche nach der Plan-Gruppe (Gruppe die xplanung24 Layer enthält)
            plan_group = None
            for child in root.children():
                from qgis.core import QgsLayerTreeGroup
                if isinstance(child, QgsLayerTreeGroup):
                    # Prüfe ob die Gruppe xplanung24 Layer enthält
                    for layer_node in child.children():
                        if hasattr(layer_node, 'layer') and layer_node.layer():
                            if layer_node.layer().customProperty("xplanung24_plan_id"):
                                plan_group = child
                                break
                    if plan_group:
                        break

            if plan_group:
                # Füge Layer am ENDE der Gruppe ein (= unten in der Layer-Liste = unter allen anderen)
                project.addMapLayer(raster_layer, False)
                num_children = len(plan_group.children())
                plan_group.insertLayer(num_children, raster_layer)

                # PPO/Point-Layer nach oben verschieben (müssen immer sichtbar sein)
                self._move_point_layers_to_top(plan_group)
            else:
                # Fallback: Am Ende des Root einfügen (unter allen Layern)
                project.addMapLayer(raster_layer, False)
                num_children = len(root.children())
                root.insertLayer(num_children, raster_layer)

            self.iface.messageBar().pushMessage(
                "XPlanung24",
                f"Raster '{layer_name}' unter dem Plan eingefügt.",
                level=Qgis.Success,
                duration=4
            )

            # Karte aktualisieren (ohne Zoom-Änderung)
            self.iface.mapCanvas().refresh()

        except requests.exceptions.RequestException as e:
            self.iface.messageBar().pushMessage(
                "XPlanung24",
                f"Download-Fehler: {str(e)}",
                level=Qgis.Critical,
                duration=5
            )
        except Exception as e:
            self.iface.messageBar().pushMessage(
                "XPlanung24",
                f"Fehler beim Laden: {str(e)}",
                level=Qgis.Critical,
                duration=5
            )

    def closeEvent(self, event):
        """Stelle sicher, dass das Map-Tool deaktiviert wird beim Schließen"""
        self._clear_highlights()
        if self.map_tool:
            self.iface.mapCanvas().unsetMapTool(self.map_tool)
        super().closeEvent(event)