# -*- coding: utf-8 -*-
import os
from pathlib import Path

from qgis.PyQt import uic
from qgis.PyQt.QtWidgets import QDialog, QFileDialog, QComboBox, QLabel, QVBoxLayout, QHBoxLayout, QWidget
from qgis.PyQt.QtCore import QUrl
from qgis.PyQt.QtGui import QDesktopServices, QIcon

from qgis.core import (
    QgsProject,
    QgsVectorLayer,
    QgsWkbTypes,
    QgsProviderRegistry,
)

FORM_CLASS, _ = uic.loadUiType(
    os.path.join(os.path.dirname(__file__), "Mod3_dialog_base.ui")
)

CNIG_URL = "https://centrodedescargas.cnig.es/CentroDescargas/siose-ar"


class Mod3Dialog(QDialog, FORM_CLASS):
    """
    Paso 1: Seleccionar SIOSE AR (GPKG) y opcionalmente cargarlo al proyecto
    Paso 2: Usar selección nativa de QGIS (flecha) para capturar AOI (polígono)
    """

    def __init__(self, iface, parent=None):
        super().__init__(parent)
        self.iface = iface
        self.setupUi(self)

        try:
            icon_path = os.path.join(os.path.dirname(__file__), "icon.png")
            self.setWindowIcon(QIcon(icon_path))
        except Exception:
            pass

        self.siose_gpkg_path = None
        self.siose_layer = None
        self.aoi_geom = None
        self.siose_sublayer_name = None

        self._aoi_select_armed = False

        self.rbTengoCorine.toggled.connect(self._update_ui_state)
        self.rbNoTengoCorine.toggled.connect(self._update_ui_state)
        self.btnAbrirCNIG.clicked.connect(self._open_cnig)
        self.btnSeleccionarArchivo.clicked.connect(self._select_gpkg)

        # Combo de subcapas SIOSE
        self.cmb_sublayer = QComboBox()
        self.cmb_sublayer.setMinimumWidth(300)
        self.cmb_sublayer.setEnabled(False)
        self.cmb_sublayer.currentIndexChanged.connect(self._on_sublayer_changed)
        lbl_sub = QLabel("Subcapa SIOSE:")
        self.grpPaso1.layout().addWidget(lbl_sub)
        self.grpPaso1.layout().addWidget(self.cmb_sublayer)

        # Ocultar botones originales de AOI y añadir combo
        self.btnPickAoi.hide()
        self.btnLimpiarAoi.hide()

        # Crear combo de capas AOI dinámico
        self.cmb_aoi_layer = QComboBox()
        self.cmb_aoi_layer.setMinimumWidth(300)
        self.cmb_aoi_layer.currentIndexChanged.connect(self._on_aoi_changed)
        # Insertar combo en el layout del grpPaso2
        self.grpPaso2.layout().insertWidget(1, self.cmb_aoi_layer)
        lbl_aoi = QLabel("Capa AOI (poligonal):")
        self.grpPaso2.layout().insertWidget(1, lbl_aoi)

        self.buttonBox.accepted.connect(self._on_accept)
        self.buttonBox.rejected.connect(self._cancel_dialog)

        self._update_ui_state()
        self._populate_aoi_combo()
        self._set_status_source(False, "Pendiente")
        self._set_status_aoi(False, "Pendiente")

    # -------------------------
    # UI state
    # -------------------------
    def _update_ui_state(self):
        self.btnAbrirCNIG.setEnabled(self.rbNoTengoCorine.isChecked())

    def _populate_aoi_combo(self):
        """Rellena el combo con capas poligonales cargadas en QGIS."""
        self.cmb_aoi_layer.clear()
        self.cmb_aoi_layer.addItem("-- Seleccione una capa --", None)
        for layer_id, layer in QgsProject.instance().mapLayers().items():
            if (hasattr(layer, 'geometryType') and
                    layer.geometryType() == QgsWkbTypes.PolygonGeometry):
                self.cmb_aoi_layer.addItem(layer.name(), layer_id)
        self._set_status_aoi(False, "Seleccione una capa poligonal")

    def _on_aoi_changed(self):
        """Actualiza el estado AOI al cambiar la selección del combo."""
        layer_id = self.cmb_aoi_layer.currentData()
        if not layer_id:
            self._set_status_aoi(False, "Seleccione una capa poligonal")
            return
        lyr = QgsProject.instance().mapLayer(layer_id)
        if lyr is None or not lyr.isValid():
            self._set_status_aoi(False, "Capa no válida")
            return
        if lyr.featureCount() == 0:
            self._set_status_aoi(False, "La capa no tiene entidades")
            return
        self._set_status_aoi(True, f"AOI OK: {lyr.name()} ({lyr.featureCount()} entidades) — CRS: {lyr.crs().authid()}")

    def _open_cnig(self):
        QDesktopServices.openUrl(QUrl(CNIG_URL))

    def _set_status_source(self, ok: bool, msg: str):
        self.lblEstado.setText(f"Estado: {msg}")
        self.lblEstado.setStyleSheet("color: green;" if ok else "color: red;")

    def _set_status_aoi(self, ok: bool, msg: str):
        self.lblAoiEstado.setText(f"AOI: {msg}")
        self.lblAoiEstado.setStyleSheet("color: green;" if ok else "color: red;")

    def _clear_aoi(self):
        self.aoi_geom = None
        self._aoi_select_armed = False
        self._set_status_aoi(False, "Pendiente")

    # -------------------------
    # Paso 1: seleccionar GPKG SIOSE AR
    # -------------------------
    def _select_gpkg(self):
        path, _ = QFileDialog.getOpenFileName(
            self,
            "Seleccionar SIOSE AR (GeoPackage)",
            "",
            "GeoPackage (*.gpkg)"
        )
        if not path:
            return

        self.txtRutaCorine.setText(path)

        try:
            gpkg_path = str(Path(path))
            if not Path(gpkg_path).exists():
                raise Exception("No se encontró el archivo .gpkg.")

            lyr = self._find_siose_layer_in_gpkg(gpkg_path)
            if lyr is None or not lyr.isValid():
                raise Exception("No se encontró una capa poligonal T_COMBINADA con el campo ID_COBERTURA_MAX dentro del GPKG.")

            self.siose_gpkg_path = gpkg_path

            # Poblar combo de subcapas con todas las que tengan ID_COBERTURA_MAX
            self._populate_sublayer_combo(gpkg_path)

            if hasattr(self, "chkCargarCorine") and self.chkCargarCorine.isChecked():
                existing = self._find_existing_layer_by_source(gpkg_path, lyr.name())
                if existing is None:
                    QgsProject.instance().addMapLayer(lyr)
                    self.siose_layer = lyr
                else:
                    self.siose_layer = existing
            else:
                self.siose_layer = lyr

            self._set_status_source(True, f"SIOSE AR OK ({self.cmb_sublayer.currentText()})")
            self._clear_aoi()

        except Exception as e:
            self.siose_gpkg_path = None
            self.siose_layer = None
            self._set_status_source(False, str(e))

    def _find_existing_layer_by_source(self, gpkg_path: str, layername: str):
        for lyr in QgsProject.instance().mapLayers().values():
            if not isinstance(lyr, QgsVectorLayer) or not lyr.isValid():
                continue
            src = lyr.source()
            if gpkg_path in src and (f"layername={layername}" in src or lyr.name() == layername):
                return lyr
        return None

    def _populate_sublayer_combo(self, gpkg_path: str):
        """Rellena el combo con todas las subcapas que tienen ID_COBERTURA_MAX."""
        self.cmb_sublayer.clear()
        self.cmb_sublayer.setEnabled(False)

        try:
            md = QgsProviderRegistry.instance().providerMetadata("ogr")
            conn = md.createConnection(gpkg_path, {})
            tables = conn.tables()

            candidates = []
            for t in tables:
                layer_name = t.tableName() if hasattr(t, "tableName") else t.name()
                uri = f"{gpkg_path}|layername={layer_name}"
                vlayer = QgsVectorLayer(uri, layer_name, "ogr")
                if not vlayer.isValid():
                    continue
                if vlayer.geometryType() != QgsWkbTypes.PolygonGeometry:
                    continue
                if "ID_COBERTURA_MAX" in [f.name() for f in vlayer.fields()]:
                    candidates.append(layer_name)

            if not candidates:
                return

            # Ordenar: COMBINADA primero
            candidates.sort(key=lambda x: (0 if "COMBINADA" in x.upper() else 1, x))

            for name in candidates:
                self.cmb_sublayer.addItem(name, name)

            self.cmb_sublayer.setEnabled(True)
            self._on_sublayer_changed()

        except Exception:
            pass

    def _on_sublayer_changed(self):
        """Actualiza siose_layer al cambiar la subcapa seleccionada."""
        if not self.siose_gpkg_path:
            return
        layer_name = self.cmb_sublayer.currentData()
        if not layer_name:
            return
        uri = f"{self.siose_gpkg_path}|layername={layer_name}"
        lyr = QgsVectorLayer(uri, layer_name, "ogr")
        if lyr.isValid():
            self.siose_layer = lyr
            self.siose_sublayer_name = layer_name
            self._set_status_source(True, f"SIOSE AR OK ({layer_name})")

    def _find_siose_layer_in_gpkg(self, gpkg_path: str) -> QgsVectorLayer:
        md = QgsProviderRegistry.instance().providerMetadata("ogr")
        conn = md.createConnection(gpkg_path, {})
        tables = conn.tables()
        if not tables:
            return None

        for t in tables:
            layer_name = t.tableName() if hasattr(t, "tableName") else t.name()
            uri = f"{gpkg_path}|layername={layer_name}"
            vlayer = QgsVectorLayer(uri, layer_name, "ogr")
            if not vlayer.isValid():
                continue
            if vlayer.geometryType() != QgsWkbTypes.PolygonGeometry:
                continue
            if "ID_COBERTURA_MAX" in [f.name() for f in vlayer.fields()]:
                return vlayer

        return None

    # -------------------------
    # Paso 2: Selección nativa de QGIS
    # -------------------------
    def _on_btn_pick_aoi(self):
        if not self.siose_gpkg_path:
            self._set_status_aoi(False, "Seleccione primero el GPKG de SIOSE AR (Paso 1).")
            return

        if not self._aoi_select_armed:
            self._aoi_select_armed = True
            try:
                self.iface.actionSelect().trigger()
            except Exception:
                pass
            self._set_status_aoi(
                False,
                "Seleccione UN polígono con la flecha de QGIS y luego haga clic en este botón nuevamente."
            )
            return

        self._capture_selected_polygon_as_aoi()
        self._aoi_select_armed = False

    def _capture_selected_polygon_as_aoi(self):
        try:
            layers = self.iface.mapCanvas().layers()
            for lyr in layers:
                if not isinstance(lyr, QgsVectorLayer) or not lyr.isValid():
                    continue
                if lyr.geometryType() != QgsWkbTypes.PolygonGeometry:
                    continue
                if lyr.selectedFeatureCount() < 1:
                    continue

                feats = lyr.selectedFeatures()
                if not feats:
                    continue

                geom = feats[0].geometry()
                if geom is None or geom.isEmpty():
                    continue

                self.aoi_geom = geom
                self._set_status_aoi(True, f"OK (seleccionado desde: {lyr.name()})")
                return

            self.aoi_geom = None
            self._set_status_aoi(False, "No se encontraron polígonos seleccionados. Seleccione un polígono y vuelva a intentarlo.")

        except Exception as e:
            self.aoi_geom = None
            self._set_status_aoi(False, str(e))

    # -------------------------
    # Checkbox disolver
    # -------------------------
    def get_dissolve_checked(self):
        if hasattr(self, "chkDissolve"):
            return self.chkDissolve.isChecked()
        return False

    # -------------------------
    # OK
    # -------------------------
    def _on_accept(self):
        if not self.siose_gpkg_path or not Path(self.siose_gpkg_path).exists():
            self._set_status_source(False, "Selecciona un archivo .gpkg de SIOSE AR válido primero.")
            return

        layer_id = self.cmb_aoi_layer.currentData()
        if not layer_id:
            self._set_status_aoi(False, "Seleccione una capa AOI poligonal.")
            return

        lyr = QgsProject.instance().mapLayer(layer_id)
        if lyr is None or not lyr.isValid():
            self._set_status_aoi(False, "Capa AOI no válida.")
            return

        # Obtener geometría combinada del AOI
        from qgis.core import QgsGeometry
        geoms = [f.geometry() for f in lyr.getFeatures()]
        if not geoms:
            self._set_status_aoi(False, "La capa AOI no tiene entidades.")
            return
        self.aoi_geom = QgsGeometry.unaryUnion(geoms)
        self.aoi_crs = lyr.crs()
        self._set_status_aoi(True, f"AOI OK: {lyr.name()} ({lyr.featureCount()} entidades)")
        self.accept()

    def _reset_dialog(self):
        """Resetea todos los campos del diálogo a su estado inicial."""
        self.siose_gpkg_path = None
        self.siose_layer = None
        self.siose_sublayer_name = None
        self.aoi_geom = None
        self.aoi_crs = None
        self._aoi_select_armed = False
        self.txtRutaCorine.clear()
        self.cmb_sublayer.clear()
        self.cmb_sublayer.setEnabled(False)
        self.rbTengoCorine.setChecked(True)
        self._populate_aoi_combo()
        self._set_status_source(False, "Pendiente")
        self._set_status_aoi(False, "Pendiente")
        self._update_ui_state()

    def _cancel_dialog(self):
        """Llamado al pulsar Cancelar — limpia y cierra."""
        self._reset_dialog()
        self.reject()

    def closeEvent(self, event):
        """Al cerrar con la X se limpia todo."""
        self._reset_dialog()
        super().closeEvent(event)

    def reset_after_execution(self):
        """Llamado desde Mod3.py tras terminar el proceso exitosamente."""
        self._reset_dialog()

