# -*- coding: utf-8 -*-
"""Quad-view labeling window.

Shows the current sample point in four synchronized views at once
(NDVI, NDWI, ESA WorldCover, Google Satellite by default) with the
class buttons beside them, so a point can be judged from several
angles without switching layers.
"""

from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import (
    QDialog, QVBoxLayout, QHBoxLayout, QGridLayout, QPushButton, QLabel,
    QSpinBox, QCheckBox, QComboBox, QWidget,
)
from qgis.core import QgsCoordinateTransform, QgsProject

from .. import gee_utils as gu
from .quad_view import QuadView


def _is_dark(hex_color):
    try:
        h = hex_color.lstrip("#")
        r, g, b = int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)
        return (0.299 * r + 0.587 * g + 0.114 * b) < 140
    except (AttributeError, TypeError, RuntimeError):  # Safe fallback
        return False


class QuadLabelWindow(QDialog):
    def __init__(self, iface, state, dock, parent=None):
        super().__init__(parent)
        self.iface = iface
        self.state = state
        self.dock = dock          # the LabelingDock drives the point list
        self.setWindowTitle("Label points - 4 synchronized views")
        self.setWindowFlags(self.windowFlags() | Qt.WindowType.Window)
        self._build()
        self.resize(1100, 780)

    def _build(self):
        root = QVBoxLayout(self)

        top = QHBoxLayout()
        self.btn_prev = QPushButton("< Prev")
        self.btn_next = QPushButton("Next >")
        self.btn_prev.clicked.connect(lambda: self._step(-1))
        self.btn_next.clicked.connect(lambda: self._step(1))
        self.lbl_pos = QLabel("0 / 0")
        self.lbl_pos.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.lbl_pos.setStyleSheet("font-weight: bold;")
        top.addWidget(self.btn_prev)
        top.addWidget(self.lbl_pos, 1)
        top.addWidget(self.btn_next)
        top.addWidget(QLabel("Zoom 1:"))
        self.sp_scale = QSpinBox()
        self.sp_scale.setRange(200, 50000); self.sp_scale.setValue(1500)
        self.sp_scale.setSingleStep(100)
        self.sp_scale.valueChanged.connect(self.refresh)
        top.addWidget(self.sp_scale)
        self.chk_auto = QCheckBox("Auto-advance")
        self.chk_auto.setChecked(True)
        top.addWidget(self.chk_auto)
        root.addLayout(top)

        mid = QHBoxLayout()
        self.quad = QuadView(self.iface, self.state)
        mid.addWidget(self.quad, 1)

        side = QWidget(); sv = QVBoxLayout(side)
        sv.addWidget(QLabel("<b>Assign class</b>"))
        grid = QGridLayout()
        # use the same scheme the dock is on (LULC / WorldCover / custom)
        classes = (self.dock._scheme_classes()
                   if hasattr(self.dock, "_scheme_classes")
                   else list(gu.LULC_CLASSES))
        for i, (code, name, color) in enumerate(classes):
            btn = QPushButton("{}. {}".format(code, name))
            btn.setMinimumHeight(38)
            dark = _is_dark(color)
            btn.setStyleSheet(
                "background-color: {}; color: {}; font-weight: bold;".format(
                    color, "white" if dark else "black"))
            btn.clicked.connect(
                lambda _, c=code, n=name: self._assign(c, n))
            grid.addWidget(btn, i, 0)
        sv.addLayout(grid)

        sv.addWidget(QLabel("Level 2 (LU2003):"))
        self.cb_l2 = QComboBox()
        self.cb_l2.activated.connect(self._assign_l2)
        sv.addWidget(self.cb_l2)

        b_skip = QPushButton("Next unlabeled")
        b_skip.clicked.connect(self._next_unlabeled)
        sv.addWidget(b_skip)
        b_clear = QPushButton("Clear label")
        b_clear.clicked.connect(lambda: self._assign(0, ""))
        sv.addWidget(b_clear)

        self.lbl_info = QLabel("-")
        self.lbl_info.setWordWrap(True)
        sv.addWidget(self.lbl_info)
        self.lbl_progress = QLabel("")
        sv.addWidget(self.lbl_progress)
        sv.addStretch()
        b_close = QPushButton("Close")
        b_close.clicked.connect(self.close)
        sv.addWidget(b_close)
        side.setMaximumWidth(240)
        mid.addWidget(side)
        root.addLayout(mid, 1)

        hint = QLabel(
            "All four panels stay in sync. Change any panel's layer with "
            "its dropdown. Defaults: NDVI, NDWI, ESA WorldCover 2021, "
            "Google Satellite.")
        hint.setStyleSheet("color:#666; font-size:11px;")
        hint.setWordWrap(True)
        root.addWidget(hint)

    # ------------------------------------------------------------ driving
    def _layer(self):
        return self.dock.current_layer()

    def _step(self, d):
        # dock.step() -> dock._refresh() -> sync_to_dock() already refreshes
        # this window, so don't refresh twice
        self.dock.step(d)
        if getattr(self.dock, "_syncing_quad", False):
            return
        self.refresh()

    def _next_unlabeled(self):
        self.dock.next_unlabeled()
        self.refresh()

    def _assign(self, code, name):
        # mirror this window's auto-advance choice into the dock
        try:
            self.dock.chk_auto.setChecked(self.chk_auto.isChecked())
        except (AttributeError, TypeError):  # Qt/QGIS API compatibility
            pass
        self.dock.assign(code, name)
        self.refresh()

    def _assign_l2(self, idx):
        """Assign a Level-2 LU2003 class directly (the dock's own combo has
        a different index, so we write the attributes here)."""
        lu = self.cb_l2.itemData(idx)
        if lu is None:
            return
        l1, abbr, name = gu.LU2003[lu]
        self.dock._set_attrs({
            "class_code": l1, "class_name": gu.l1_name(l1),
            "lu_code": lu, "lu_name": name})
        if self.chk_auto.isChecked():
            self.dock.step(1)
        self.refresh()

    def sync_to_dock(self):
        """Refresh the four panels to the dock's CURRENT point, without
        driving the dock again (used when the main window navigated)."""
        self.refresh()

    def refresh(self):
        lyr = self._layer()
        if lyr is None or not self.dock.fids:
            self.lbl_pos.setText("0 / 0")
            return
        fid = self.dock.fids[self.dock.pos]
        f = lyr.getFeature(fid)
        self.lbl_pos.setText("{} / {}".format(
            self.dock.pos + 1, len(self.dock.fids)))
        fields = f.fields().names()
        hint = ""
        if "wc_hint" in fields and f["wc_hint"]:
            hint = "<br>WorldCover hint: <b>{}</b>".format(f["wc_hint"])
        self.lbl_info.setText(
            "point_id: {}<br>class: <b>{}</b><br>use: {}{}".format(
                f["point_id"] if "point_id" in fields else fid,
                f["class_name"] or "-", f["use"] or "-", hint))
        labeled = sum(1 for ft in lyr.getFeatures()
                      if int(ft["class_code"] or 0) > 0)
        self.lbl_progress.setText(
            "Labeled: {} / {}".format(labeled, lyr.featureCount()))

        # L2 list for the current class
        code = int(f["class_code"] or 0)
        self.cb_l2.clear()
        self.cb_l2.addItem("(choose detail class ...)", None)
        if code > 0:
            for lu, abbr, nm in gu.l2_classes_for(code):
                self.cb_l2.addItem("{} {} - {}".format(lu, abbr, nm), lu)

        lyr.selectByIds([fid])
        self.quad.refresh_all(lyr)
        # center all four panels on the point
        try:
            crs = self.quad.canvases[0].mapSettings().destinationCrs()
            ct = QgsCoordinateTransform(lyr.crs(), crs,
                                        QgsProject.instance())
            pt = ct.transform(f.geometry().asPoint())
            self.quad.set_center(pt, self.sp_scale.value())
        except (AttributeError, TypeError, RuntimeError):  # QGIS geometry
            pass

    def showEvent(self, e):
        super().showEvent(e)
        try:
            # Provide five reference layers in the main canvas:
            #   sample_points (top), Google Satellite, ESA WorldCover 2021
            #   (visible), Index: NDVI, Index: NDWI (present but unchecked).
            gu.add_google_satellite()
            gu.add_worldcover_layer()
            # order: points on top, then the index layers just beneath them,
            # then the basemaps
            gu.order_reference_layers(
                top="sample_points",
                below_points=("Index: NDVI", "Index: NDWI"),
                visible=("sample_points", "Google Satellite",
                         "ESA WorldCover 2021"),
                unchecked=("Index: NDVI", "Index: NDWI"),
                hide_prefixes=("Stack ", "Sentinel-2", "Sentinel-1",
                               "Landsat", "Composite ", "True color"))
        except (AttributeError, TypeError):  # Qt/QGIS API compatibility
            pass
        self.refresh()
