import os
import re

from qgis.core import QgsApplication
from qgis.PyQt import QtWidgets
from qgis.PyQt.QtCore import pyqtSlot

from ..compat import MESSAGE_LEVEL_CRITICAL, MESSAGE_LEVEL_SUCCESS, USER_ROLE
from ..gp.vectorize_task import VectorizeTask
from ..model.db_item import DBItemModel
from ..model.project import Project
from ..model.scratch_vector import get_unique_scratch_fc_name, insert_scratch_vector, scratch_gpkg_path
from ..QRiS.path_utilities import parse_posix_path
from ..QRiS.settings import Settings
from .utilities import add_standard_form_buttons, validate_name, validate_name_unique


class FrmSliderScratchVector(QtWidgets.QDialog):
    def __init__(self, parent, qris_project: Project, raster_path: str, threshold_value: float, inverse: bool = False) -> None:
        super().__init__(parent)

        self.setupUi()

        self.qris_project = qris_project
        self.raster_path = raster_path
        self.threshold_value = threshold_value
        self.scratch_vector = None
        self.inverse = inverse

        self.setWindowTitle("Export Polygon to Scratch Vector")

        self.vector_types_model = DBItemModel(qris_project.lookup_tables["lkp_scratch_vector_types"])
        self.cboVectorType.setModel(self.vector_types_model)

        self.txtName.textChanged.connect(self.on_name_changed)

        self.dbsSimplifyTolerance.setDecimals(5)
        self.dbsSimplifyTolerance.setRange(0.00000, 0.0001)
        self.dbsSimplifyTolerance.setSingleStep(0.00001)
        self.dbsSimplifyTolerance.setValue(0.0001)

        self.dbsSmoothingOffset.setRange(0.0, 0.75)
        self.dbsSmoothingOffset.setSingleStep(0.05)
        self.dbsSmoothingOffset.setValue(0.5)

        self.dbsMinPolygonSize.setDecimals(1)
        self.dbsMinPolygonSize.setMinimum(0.0)
        self.dbsMinPolygonSize.setValue(9.0)

    def accept(self):

        if not validate_name(self, self.txtName):
            return

        if validate_name_unique(self.qris_project.project_file, "scratch_vectors", "name", self.txtName.text()) is False:
            QtWidgets.QMessageBox.warning(self, "Duplicate Name", f"A scratch vector with the name '{self.txtName.text()}' already exists. Please choose a unique name.")
            self.txtName.setFocus()
            return

        try:
            self.fc_name = get_unique_scratch_fc_name(self.qris_project.project_file, self.txtName.text())

            simplify_value = self.dbsSimplifyTolerance.value()
            smoothing_value = self.dbsSmoothingOffset.value()
            min_area_value = self.dbsMinPolygonSize.value()
            gpkg = os.path.dirname(self.txtProjectPath.text())

            vectorize_task = VectorizeTask(self.raster_path, gpkg, self.fc_name, self.threshold_value, simplify_value, smoothing_value, min_area_value, self.inverse)

            # --DEBUG--
            # result = vectorize_task.run()  # DEBUG
            # self.on_complete(result)

            # --PRODUCTION--
            vectorize_task.on_complete.connect(self.on_complete)
            # self.buttonBox.setEnabled(False)
            QgsApplication.taskManager().addTask(vectorize_task)

        except Exception as ex:
            # self.buttonBox.setEnabled(True)
            self.scratch_vector = None
            QtWidgets.QMessageBox.warning(self, "Error Vectorizing Raster", str(ex))
            return

    @pyqtSlot(bool)
    def on_complete(self, result: bool):

        if result is True:
            try:
                gpkg = os.path.dirname(self.txtProjectPath.text())
                self.scratch_vector = insert_scratch_vector(self.qris_project.project_file, self.txtName.text(), self.fc_name, gpkg, self.cboVectorType.currentData(USER_ROLE).id, self.txtDescription.toPlainText())
                self.qris_project.add_db_item(self.scratch_vector)
                Settings().msg_bar("Vectorize Raster Complete", f"{self.txtName.text()} saved successfully.", MESSAGE_LEVEL_SUCCESS)
            except Exception as ex:
                if "unique" in str(ex).lower():
                    QtWidgets.QMessageBox.warning(self, "Duplicate Name", f"A scratch vector with the name '{self.txtName.text()}' already exists. Please choose a unique name.")
                    self.txtName.setFocus()
                else:
                    QtWidgets.QMessageBox.warning(self, "Error Saving Vector", str(ex))
                return

            super().accept()
        else:
            Settings().msg_bar("Vectorize Raster Error", "Review the QGIS log.", MESSAGE_LEVEL_CRITICAL)
            # self.buttonBox.setEnabled(True)

    def on_name_changed(self, new_name):

        clean_name = re.sub("[^A-Za-z0-9]+", "", self.txtName.text())
        if len(clean_name) > 0:
            self.txtProjectPath.setText(parse_posix_path(os.path.join(scratch_gpkg_path(self.qris_project.project_file), clean_name)))
        else:
            self.txtProjectPath.setText("")

    def setupUi(self):

        self.resize(500, 400)
        self.setMinimumSize(400, 300)

        # Top level layout must include parent. Widgets added to this layout do not need parent.
        self.vert = QtWidgets.QVBoxLayout(self)
        self.setLayout(self.vert)

        self.grid = QtWidgets.QGridLayout()
        self.vert.addLayout(self.grid)

        self.lblName = QtWidgets.QLabel("Name")
        self.grid.addWidget(self.lblName, 0, 0, 1, 1)

        self.txtName = QtWidgets.QLineEdit()
        self.txtName.setToolTip("Name of the saved vector layer")
        self.txtName.setMaxLength(255)
        self.grid.addWidget(self.txtName, 0, 1, 1, 1)

        self.lblProjectPath = QtWidgets.QLabel("Project Path")
        self.grid.addWidget(self.lblProjectPath, 1, 0, 1, 1)

        self.txtProjectPath = QtWidgets.QLineEdit()
        self.txtProjectPath.setReadOnly(True)
        self.grid.addWidget(self.txtProjectPath, 1, 1, 1, 1)

        self.lblVectorType = QtWidgets.QLabel("Vector Type")
        self.grid.addWidget(self.lblVectorType, 2, 0, 1, 1)

        self.cboVectorType = QtWidgets.QComboBox()
        self.cboVectorType.setToolTip("Type of vector data")
        self.grid.addWidget(self.cboVectorType, 2, 1, 1, 1)

        self.lblSimplifyTolerance = QtWidgets.QLabel("Simplify Tolerance")
        self.grid.addWidget(self.lblSimplifyTolerance, 3, 0, 1, 1)

        self.dbsSimplifyTolerance = QtWidgets.QDoubleSpinBox()
        self.dbsSimplifyTolerance.setToolTip("Simplify tolerance for vectorization")
        self.grid.addWidget(self.dbsSimplifyTolerance, 3, 1, 1, 1)

        self.lblSmoothingOffset = QtWidgets.QLabel("Smooting Offset")
        self.grid.addWidget(self.lblSmoothingOffset, 4, 0, 1, 1)

        self.dbsSmoothingOffset = QtWidgets.QDoubleSpinBox()
        self.dbsSmoothingOffset.setToolTip("Smoothing offset for vectorization")
        self.grid.addWidget(self.dbsSmoothingOffset, 4, 1, 1, 1)

        self.lblMinPolygonSize = QtWidgets.QLabel("Minimum Polygon Area")
        self.grid.addWidget(self.lblMinPolygonSize, 5, 0, 1, 1)

        self.dbsMinPolygonSize = QtWidgets.QDoubleSpinBox()
        self.dbsMinPolygonSize.setToolTip("Minimum polygon area for vectorization")
        self.grid.addWidget(self.dbsMinPolygonSize, 5, 1, 1, 1)

        # self.lblMask = QtWidgets.QLabel()
        # self.lblMask.setText('Clip to AOI')
        # self.grid.addWidget(self.lblMask, 4, 0, 1, 1)

        # self.cboMask = QtWidgets.QComboBox()
        # self.grid.addWidget(self.cboMask, 4, 1, 1, 1)

        self.lblDescription = QtWidgets.QLabel("Description")
        self.grid.addWidget(self.lblDescription, 6, 0, 1, 1)

        self.txtDescription = QtWidgets.QPlainTextEdit()
        self.grid.addWidget(self.txtDescription, 6, 1, 1, 1)

        self.chkAddToMap = QtWidgets.QCheckBox()
        self.chkAddToMap.setText("Add to Map")
        self.chkAddToMap.setChecked(True)
        self.grid.addWidget(self.chkAddToMap, 7, 1, 1, 1)

        self.vert.addLayout(add_standard_form_buttons(self, "inputs/surfaces/#raster-slider-tool"))
