import re
from datetime import datetime
from PyQt5 import QtWidgets, QtCore, QtGui

TYPE_OPTIONS = [
    ("question", "Frage"),
    ("error", "Fehler"),
    ("reminder", "Erinnerung"),
    ("request", "Korrekturwunsch"),
    ("additional", "Änderung"),
]

STATUS_OPTIONS = [
    ("open", "Offen"),
    ("done", "Abgenommen"),
]


def _add_point_to_annotation_layer(location, result, review_data):
    """Fügt den gesetzten Punkt zum Anmerkungs-Layer hinzu. Erstellt den Layer falls nötig."""
    from qgis.core import (
        QgsProject, QgsFeature, QgsGeometry, QgsPointXY,
        QgsVectorLayer, QgsField, QgsMarkerSymbol,
        QgsSimpleMarkerSymbolLayer, QgsFontMarkerSymbolLayer,
        QgsCategorizedSymbolRenderer, QgsRendererCategory,
        QgsTextFormat, QgsTextBufferSettings,
        QgsPalLayerSettings, QgsVectorLayerSimpleLabeling,
    )
    from PyQt5.QtCore import QVariant
    from qgis.PyQt.QtGui import QColor, QFont
    from ..utils.document_list import TYPE_LABELS, STATUS_LABELS, TYPE_COLORS, TYPE_ICONS

    layers = QgsProject.instance().mapLayersByName("Abnahme-Anmerkungen")

    if not layers:
        # Layer existiert nicht - erstelle ihn
        mem_layer = QgsVectorLayer("Point?crs=EPSG:4326", "Abnahme-Anmerkungen", "memory")
        dp = mem_layer.dataProvider()

        dp.addAttributes([
            QgsField("task_id", QVariant.String),
            QgsField("name", QVariant.String),
            QgsField("typ", QVariant.String),
            QgsField("status", QVariant.String),
            QgsField("beschreibung", QVariant.String),
        ])
        mem_layer.updateFields()

        # Kategorisiertes Styling nach Typ mit Icons
        categories = []
        for type_key, color in TYPE_COLORS.items():
            label = TYPE_LABELS.get(type_key, type_key)
            char = TYPE_ICONS.get(type_key, "?")

            symbol = QgsMarkerSymbol()
            symbol.deleteSymbolLayer(0)

            # Farbiger Kreis als Hintergrund
            bg = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Circle, 6.0)
            bg.setColor(QColor(color))
            bg.setStrokeColor(QColor("#ffffff"))
            bg.setStrokeWidth(0.4)
            symbol.appendSymbolLayer(bg)

            # Typ-Zeichen auf dem Kreis
            char_layer = QgsFontMarkerSymbolLayer()
            char_layer.setFontFamily("Sans Serif")
            char_layer.setCharacter(char)
            char_layer.setSize(3.5)
            char_layer.setColor(QColor("#ffffff"))
            symbol.appendSymbolLayer(char_layer)

            categories.append(QgsRendererCategory(label, symbol, label))

        renderer = QgsCategorizedSymbolRenderer("typ", categories)
        mem_layer.setRenderer(renderer)

        # Text-Labels mit Name der Anmerkung
        pal = QgsPalLayerSettings()
        pal.fieldName = "name"
        pal.enabled = True

        text_format = QgsTextFormat()
        text_format.setFont(QFont("Sans Serif", 8))
        text_format.setSize(8)
        text_format.setColor(QColor("#333333"))

        buf = QgsTextBufferSettings()
        buf.setEnabled(True)
        buf.setSize(1.2)
        buf.setColor(QColor("#ffffff"))
        text_format.setBuffer(buf)

        pal.setFormat(text_format)

        mem_layer.setLabeling(QgsVectorLayerSimpleLabeling(pal))
        mem_layer.setLabelsEnabled(True)

        QgsProject.instance().addMapLayer(mem_layer)
        layer = mem_layer
    else:
        layer = layers[0]
    coords = location["geometry"]["coordinates"]

    feat = QgsFeature(layer.fields())
    feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(coords[0], coords[1])))
    feat.setAttribute("task_id", result.get("id", ""))
    feat.setAttribute("name", review_data["name"])
    feat.setAttribute("typ", TYPE_LABELS.get(review_data["type"], review_data["type"]))
    feat.setAttribute("status", STATUS_LABELS.get("open", "Offen"))
    feat.setAttribute("beschreibung", (review_data.get("message") or "")[:200])

    layer.dataProvider().addFeatures([feat])
    layer.updateExtents()
    layer.triggerRepaint()


def _remove_point_from_annotation_layer(task_id):
    """Entfernt einen Punkt aus dem Anmerkungs-Layer anhand der task_id."""
    from qgis.core import QgsProject

    layers = QgsProject.instance().mapLayersByName("Abnahme-Anmerkungen")
    if not layers:
        return

    layer = layers[0]
    to_delete = []
    for feat in layer.getFeatures():
        if feat["task_id"] == task_id:
            to_delete.append(feat.id())

    if to_delete:
        layer.dataProvider().deleteFeatures(to_delete)
        layer.updateExtents()
        layer.triggerRepaint()


class ReviewDetailsDialog(QtWidgets.QDialog):
    """Dialog zum Anzeigen / Bearbeiten eines Review-Eintrags."""

    saved = QtCore.pyqtSignal()
    deleted = QtCore.pyqtSignal()

    def __init__(self, review: dict, user_status: str,
                 cognito_session=None, order_id: str = "", parent=None):
        super().__init__(parent)
        self.review = dict(review)
        self.user_status = user_status
        self.cognito_session = cognito_session
        self.order_id = order_id
        self._is_owner = user_status == "orderOwner"

        self.setWindowTitle("Eintragsdetails")
        self.resize(560, 520)
        self._build_ui()

    # ------------------------------------------------------------------
    def _build_ui(self):
        layout = QtWidgets.QVBoxLayout(self)

        # --- Art & Status ---
        row = QtWidgets.QHBoxLayout()

        type_group = QtWidgets.QVBoxLayout()
        type_group.addWidget(QtWidgets.QLabel("Art"))
        self.type_combo = QtWidgets.QComboBox()
        for val, label in TYPE_OPTIONS:
            self.type_combo.addItem(label, val)
        idx = self.type_combo.findData(self.review.get("type", "question"))
        if idx >= 0:
            self.type_combo.setCurrentIndex(idx)
        self.type_combo.setEnabled(self._is_owner)
        type_group.addWidget(self.type_combo)
        row.addLayout(type_group)

        status_group = QtWidgets.QVBoxLayout()
        status_group.addWidget(QtWidgets.QLabel("Status"))
        self.status_combo = QtWidgets.QComboBox()
        for val, label in STATUS_OPTIONS:
            self.status_combo.addItem(label, val)
        idx = self.status_combo.findData(self.review.get("status", "open"))
        if idx >= 0:
            self.status_combo.setCurrentIndex(idx)
        self.status_combo.setEnabled(self._is_owner)
        status_group.addWidget(self.status_combo)
        row.addLayout(status_group)

        layout.addLayout(row)

        # --- Titel ---
        layout.addWidget(QtWidgets.QLabel("Titel"))
        self.name_edit = QtWidgets.QLineEdit(self.review.get("name", ""))
        self.name_edit.setReadOnly(not self._is_owner)
        layout.addWidget(self.name_edit)

        # --- Beschreibung ---
        layout.addWidget(QtWidgets.QLabel("Beschreibung"))
        self.desc_display = QtWidgets.QTextEdit()
        self.desc_display.setReadOnly(True)
        self._render_description(self.review.get("message", ""))
        layout.addWidget(self.desc_display)

        # --- Anmerkung hinzufügen ---
        self.note_container = QtWidgets.QWidget()
        note_layout = QtWidgets.QVBoxLayout(self.note_container)
        note_layout.setContentsMargins(0, 0, 0, 0)

        self.add_note_btn = QtWidgets.QPushButton("Anmerkung hinzufügen")
        self.add_note_btn.setStyleSheet(
            "color: #1d4ed8; border: 1px dashed #60a5fa; padding: 4px 8px;"
        )
        self.add_note_btn.clicked.connect(self._show_note_input)
        note_layout.addWidget(self.add_note_btn, alignment=QtCore.Qt.AlignLeft)

        self.note_meta_label = QtWidgets.QLabel()
        self.note_meta_label.setStyleSheet("font-size: 11px; color: gray;")
        self.note_meta_label.setVisible(False)
        note_layout.addWidget(self.note_meta_label)

        self.note_edit = QtWidgets.QTextEdit()
        self.note_edit.setFixedHeight(60)
        self.note_edit.setPlaceholderText("Anmerkung...")
        self.note_edit.setVisible(False)
        note_layout.addWidget(self.note_edit)

        self.cancel_note_btn = QtWidgets.QPushButton("Abbrechen")
        self.cancel_note_btn.setVisible(False)
        self.cancel_note_btn.clicked.connect(self._hide_note_input)
        note_layout.addWidget(self.cancel_note_btn, alignment=QtCore.Qt.AlignLeft)

        layout.addWidget(self.note_container)

        # --- Buttons ---
        btn_layout = QtWidgets.QHBoxLayout()

        if self._is_owner:
            self.delete_btn = QtWidgets.QPushButton("Löschen")
            self.delete_btn.setStyleSheet(
                "color: #dc2626; border: 2px solid #dc2626; padding: 6px 16px;"
            )
            self.delete_btn.clicked.connect(self._on_delete)
            btn_layout.addWidget(self.delete_btn)

        btn_layout.addStretch()

        self.save_btn = QtWidgets.QPushButton("Speichern")
        self.save_btn.setStyleSheet(
            "border: 2px solid #111827; padding: 6px 16px; font-weight: bold;"
        )
        self.save_btn.clicked.connect(self._on_save)
        btn_layout.addWidget(self.save_btn)

        layout.addLayout(btn_layout)

    # ------------------------------------------------------------------
    def _render_description(self, message: str):
        """Rendert die Beschreibung mit <<<NOTE>>>-Blöcken."""
        if not message:
            self.desc_display.setPlainText("")
            return

        parts = re.split(r'(<<<NOTE>>>[\s\S]*?<<<ENDNOTE>>>)', message)
        html_parts = []
        for part in parts:
            if part.startswith('<<<NOTE>>>'):
                content = part.replace('<<<NOTE>>>', '').replace('<<<ENDNOTE>>>', '')
                lines = content.split('\n', 1)
                meta = lines[0] if lines else ""
                note_text = lines[1] if len(lines) > 1 else ""
                html_parts.append(
                    f'<div style="margin: 8px 0; padding: 6px 10px; '
                    f'border-left: 4px solid #6b7280; background: #f3f4f6;">'
                    f'<div style="font-size: 11px; color: #6b7280;">{meta}</div>'
                    f'<div style="color: #374151;">{note_text}</div></div>'
                )
            else:
                text = part.strip()
                if text:
                    html_parts.append(f'<div style="margin-bottom: 4px;">{text}</div>')

        self.desc_display.setHtml(''.join(html_parts))

    # ------------------------------------------------------------------
    def _show_note_input(self):
        self.add_note_btn.setVisible(False)
        user_name = ""
        if self.cognito_session:
            user_name = self.cognito_session.user_name or ""
        date_str = datetime.now().strftime("%d.%m.%Y")
        meta = f"Anmerkung vom {date_str}"
        if user_name:
            meta += f" von {user_name}"
        self.note_meta_label.setText(meta)
        self.note_meta_label.setVisible(True)
        self.note_edit.setVisible(True)
        self.cancel_note_btn.setVisible(True)

    def _hide_note_input(self):
        self.note_edit.clear()
        self.note_edit.setVisible(False)
        self.note_meta_label.setVisible(False)
        self.cancel_note_btn.setVisible(False)
        self.add_note_btn.setVisible(True)

    # ------------------------------------------------------------------
    def _on_save(self):
        from ..utils.api import APIPostOrderReview

        updated = {}
        updated["id"] = self.review.get("id")
        updated["name"] = self.name_edit.text().strip()
        updated["type"] = self.type_combo.currentData()
        updated["status"] = self.status_combo.currentData()

        # Beschreibung: Originalnachricht + ggf. neue Anmerkung
        message = self.review.get("message", "") or ""
        note_text = self.note_edit.toPlainText().strip()
        if note_text:
            user_name = ""
            if self.cognito_session:
                user_name = self.cognito_session.user_name or ""
            date_str = datetime.now().strftime("%d.%m.%Y")
            author = f"von {user_name}" if user_name else ""
            note_block = f"\n<<<NOTE>>>Anmerkung vom {date_str} {author}\n{note_text}<<<ENDNOTE>>>"
            message += note_block

        updated["message"] = message
        updated["newCreation"] = False

        if not updated["name"]:
            QtWidgets.QMessageBox.warning(self, "Fehler", "Titel darf nicht leer sein.")
            return

        try:
            APIPostOrderReview(self.cognito_session, self.order_id, updated)
            self.saved.emit()
            self.accept()
        except Exception as e:
            QtWidgets.QMessageBox.critical(self, "Fehler", f"Speichern fehlgeschlagen:\n{e}")

    def _on_delete(self):
        from ..utils.api import APIDeleteOrderReview

        reply = QtWidgets.QMessageBox.question(
            self, "Eintrag löschen",
            "Möchten Sie diesen Eintrag wirklich löschen?",
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
        )
        if reply != QtWidgets.QMessageBox.Yes:
            return

        try:
            task_id = self.review.get("id")
            APIDeleteOrderReview(self.cognito_session, self.order_id, task_id)

            # Punkt aus dem Anmerkungs-Layer entfernen (deferred)
            QtCore.QTimer.singleShot(0, lambda: _remove_point_from_annotation_layer(task_id))

            self.deleted.emit()
            self.accept()
        except Exception as e:
            QtWidgets.QMessageBox.critical(self, "Fehler", f"Löschen fehlgeschlagen:\n{e}")


class ReviewCreateDialog(QtWidgets.QDialog):
    """Dialog zum Erstellen eines neuen Review-Eintrags."""

    saved = QtCore.pyqtSignal()

    def __init__(self, order_id: str, cognito_session=None, parent=None):
        super().__init__(parent)
        self.order_id = order_id
        self.cognito_session = cognito_session
        self._location = None
        self._point_tool = None
        self._prev_tool = None
        self._hidden_dialogs = []
        self._rubber_band = None

        self.setWindowTitle("Eintrag erfassen")
        self.resize(480, 400)
        self._build_ui()

    def _build_ui(self):
        layout = QtWidgets.QVBoxLayout(self)

        # --- Art ---
        layout.addWidget(QtWidgets.QLabel("Art"))
        self.type_combo = QtWidgets.QComboBox()
        for val, label in TYPE_OPTIONS:
            self.type_combo.addItem(label, val)
        layout.addWidget(self.type_combo)

        # --- Titel ---
        layout.addWidget(QtWidgets.QLabel("Titel"))
        self.name_edit = QtWidgets.QLineEdit()
        self.name_edit.setPlaceholderText("Titel")
        layout.addWidget(self.name_edit)

        # --- Beschreibung ---
        layout.addWidget(QtWidgets.QLabel("Beschreibung"))
        self.message_edit = QtWidgets.QTextEdit()
        self.message_edit.setPlaceholderText("Beschreibung")
        layout.addWidget(self.message_edit)

        # --- Punkt-Indikator ---
        self.location_label = QtWidgets.QLabel("")
        self.location_label.setStyleSheet("color: #16a34a; font-size: 11px;")
        layout.addWidget(self.location_label)

        # --- Buttons ---
        layout.addStretch()
        btn_layout = QtWidgets.QHBoxLayout()

        self.point_btn = QtWidgets.QPushButton("Punkt setzen")
        self.point_btn.setStyleSheet(
            "border: 2px solid #2563eb; color: #2563eb; padding: 6px 16px; font-weight: bold;"
        )
        self.point_btn.clicked.connect(self._on_set_point)
        btn_layout.addWidget(self.point_btn)

        btn_layout.addStretch()

        self.save_btn = QtWidgets.QPushButton("Speichern")
        self.save_btn.setStyleSheet(
            "border: 2px solid #111827; padding: 6px 16px; font-weight: bold;"
        )
        self.save_btn.clicked.connect(self._on_save)
        btn_layout.addWidget(self.save_btn)

        layout.addLayout(btn_layout)

    def _on_set_point(self):
        """Versteckt Dialoge und aktiviert Punkt-Setzen auf der Karte."""
        from qgis.gui import QgsMapToolEmitPoint, QgsRubberBand
        from qgis.utils import iface
        from qgis.core import (
            QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsProject,
            QgsWkbTypes, QgsGeometry, QgsPointXY,
        )
        from qgis.PyQt.QtGui import QColor

        canvas = iface.mapCanvas()
        self._prev_tool = canvas.mapTool()

        # Alten Vorschau-Punkt entfernen
        self._cleanup_rubber_band()

        # Dialoge verstecken
        self._hidden_dialogs = []
        self.hide()
        self._hidden_dialogs.append(self)
        parent = self.parent()
        while parent:
            if isinstance(parent, QtWidgets.QDialog):
                parent.hide()
                self._hidden_dialogs.append(parent)
            parent = parent.parent()

        self._point_tool = QgsMapToolEmitPoint(canvas)

        def on_canvas_clicked(point, button):
            # Nur Linksklick
            if button != QtCore.Qt.LeftButton:
                return

            # Koordinaten nach WGS84 transformieren
            canvas_crs = canvas.mapSettings().destinationCrs()
            wgs84 = QgsCoordinateReferenceSystem("EPSG:4326")
            if canvas_crs.authid() != "EPSG:4326":
                transform = QgsCoordinateTransform(canvas_crs, wgs84, QgsProject.instance())
                wgs84_point = transform.transform(point)
            else:
                wgs84_point = point

            self._location = {
                "type": "Feature",
                "geometry": {
                    "type": "Point",
                    "coordinates": [wgs84_point.x(), wgs84_point.y()]
                }
            }

            # Vorschau-Punkt auf der Karte anzeigen
            self._cleanup_rubber_band()
            self._rubber_band = QgsRubberBand(canvas, QgsWkbTypes.PointGeometry)
            self._rubber_band.setColor(QColor("#2563eb"))
            self._rubber_band.setSecondaryStrokeColor(QColor("#ffffff"))
            self._rubber_band.setWidth(2)
            self._rubber_band.setIconSize(12)
            self._rubber_band.setToGeometry(
                QgsGeometry.fromPointXY(QgsPointXY(point.x(), point.y())), None
            )

            # Dialoge wiederherstellen
            for dlg in reversed(self._hidden_dialogs):
                dlg.show()
                dlg.raise_()
                dlg.activateWindow()
            self._hidden_dialogs = []

            # Vorheriges Tool wiederherstellen
            if self._prev_tool:
                canvas.setMapTool(self._prev_tool)

            # UI aktualisieren
            self.location_label.setText(
                f"Punkt gesetzt: {wgs84_point.y():.6f}, {wgs84_point.x():.6f}"
            )
            self.point_btn.setText("Punkt ändern")

            iface.messageBar().clearWidgets()

        self._point_tool.canvasClicked.connect(on_canvas_clicked)

        # Wenn der User das Tool wechselt (z.B. Escape), Dialoge wiederherstellen
        self._point_tool.deactivated.connect(self._restore_dialogs_if_hidden)

        canvas.setMapTool(self._point_tool)

        iface.messageBar().pushMessage(
            "XPlanung24",
            "Klicken Sie auf die Karte, um den Punkt zu setzen. Escape zum Abbrechen.",
            level=0,
            duration=0
        )

    def _restore_dialogs_if_hidden(self):
        """Stellt versteckte Dialoge wieder her (z.B. bei Abbruch)."""
        if self._hidden_dialogs:
            for dlg in reversed(self._hidden_dialogs):
                dlg.show()
                dlg.raise_()
                dlg.activateWindow()
            self._hidden_dialogs = []
            from qgis.utils import iface
            iface.messageBar().clearWidgets()

    def _cleanup_rubber_band(self):
        """Entfernt den Vorschau-Punkt von der Karte."""
        if self._rubber_band:
            from qgis.utils import iface
            iface.mapCanvas().scene().removeItem(self._rubber_band)
            self._rubber_band = None

    def done(self, result):
        """Aufräumen beim Schließen des Dialogs."""
        self._cleanup_rubber_band()
        super().done(result)

    def _on_save(self):
        from ..utils.api import APIPostOrderReview

        name = self.name_edit.text().strip()
        message = self.message_edit.toPlainText().strip()

        if not name or not message:
            QtWidgets.QMessageBox.warning(self, "Fehler", "Titel und Beschreibung sind Pflichtfelder.")
            return

        review_data = {
            "name": name,
            "message": message,
            "type": self.type_combo.currentData(),
            "status": "open",
            "newCreation": True,
        }

        if self._location:
            review_data["location"] = self._location

        # Rubber band VOR QGIS-Layer-Operationen aufräumen
        self._cleanup_rubber_band()

        try:
            result = APIPostOrderReview(self.cognito_session, self.order_id, review_data)

            # Punkt zum Anmerkungs-Layer hinzufügen (deferred, ohne self-Referenz)
            location = self._location
            if location:
                QtCore.QTimer.singleShot(
                    0, lambda: _add_point_to_annotation_layer(location, result, review_data)
                )

            self.saved.emit()
            self.accept()
        except Exception as e:
            QtWidgets.QMessageBox.critical(self, "Fehler", f"Speichern fehlgeschlagen:\n{e}")
