# -*- coding: utf-8 -*-
#
#   Copyright (C) 2019 Oslandia <infos@oslandia.com>
#
#   This file is a piece of free software; you can redistribute it and/or
#   modify it under the terms of the GNU Library General Public
#   License as published by the Free Software Foundation; either
#   version 2 of the License, or (at your option) any later version.
#
#   This library is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#   Library General Public License for more details.
#   You should have received a copy of the GNU Library General Public
#   License along with this library; if not, see <http://www.gnu.org/licenses/>.
#

import json
import os

from qgis.PyQt.QtCore import Qt, pyqtSignal, QSettings, QCoreApplication, QTranslator
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction, QDockWidget, QFileDialog, QCheckBox, QDialog, QVBoxLayout

from qgis.core import (
    QgsPoint,
    QgsCoordinateTransform,
    QgsRectangle,
    QgsGeometry,
    QgsFeatureRequest,
    QgsProject,
    QgsWkbTypes,
)
from qgis.gui import QgsMapTool

from .configure_plot_dialog import ConfigurePlotDialog
from .main_dialog import MainDialog
from .config import import_config, export_config, remove_layer_from_config


def tr(message):
    """Get the translation for a string using Qt translation API.
    """
    # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
    return QCoreApplication.translate("@default", message)


class FeatureSelectionTool(QgsMapTool):
    pointClicked = pyqtSignal(QgsPoint)
    rightClicked = pyqtSignal(QgsPoint)
    featureSelected = pyqtSignal(list)

    def __init__(self, canvas, layer, tolerance_px=5):
        super(FeatureSelectionTool, self).__init__(canvas)
        self.setCursor(Qt.CrossCursor)
        self.__layer = layer
        self.__tolerance_px = tolerance_px

    def canvasMoveEvent(self, event):
        pass

    def canvasPressEvent(self, event):
        # Get the click
        x = event.pos().x()
        y = event.pos().y()
        tr = self.canvas().getCoordinateTransform()
        point = tr.toMapCoordinates(x, y)
        if event.button() == Qt.RightButton:
            self.rightClicked.emit(QgsPoint(point.x(), point.y()))
        else:
            self.pointClicked.emit(QgsPoint(point.x(), point.y()))

            canvas_rect = QgsRectangle(
                tr.toMapCoordinates(x - self.__tolerance_px, y - self.__tolerance_px),
                tr.toMapCoordinates(x + self.__tolerance_px, y + self.__tolerance_px),
            )

            ct = QgsCoordinateTransform(
                self.canvas().mapSettings().destinationCrs(),
                self.__layer.crs(),
                QgsProject.instance().transformContext(),
            )
            box = QgsGeometry.fromRect(canvas_rect)
            box.transform(ct)

            req = QgsFeatureRequest()
            req.setFilterRect(box.boundingBox())
            req.setFlags(QgsFeatureRequest.ExactIntersect)
            features = list(self.__layer.getFeatures(req))
            if features:
                self.featureSelected.emit(features)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return True

    def isEditTool(self):
        return True


class QGeoloGISPlugin:
    def __init__(self, iface):
        """ Main QGeoloGIS class

        :param iface: qgis interface
        :type iface: QgisInterface
        """
        self.iface = iface
        self.__config = None

        locale = QSettings().value("locale/userLocale") or "en_USA"
        locale = locale[0:2]
        locale_path = os.path.join(
            os.path.dirname(__file__), "i18n", "qgeologis_{}.qm".format(locale)
        )

        print("TRADUCTION", locale_path)

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path, "thyrsis")
            QCoreApplication.installTranslator(self.translator)
            print("TRADUCTION CHARGEE", locale_path)

        self.update_layer_config()
        QgsProject.instance().readProject.connect(self.update_layer_config)
        QgsProject.instance().cleared.connect(self.update_layer_config)

        # current map tool
        self.__tool = None

        # Root widget, to attach children to
        self.__docks = []

    def initGui(self):
        """ Init graphic interface """
        icon = QIcon(os.path.join(os.path.dirname(__file__), "qgeologis/img/plot.svg"))
        self.view_logs = QAction(icon, tr("View log plots"), self.iface.mainWindow())
        self.view_logs.setCheckable(True)
        self.view_logs.triggered.connect(lambda: self.on_view_plots(self.view_logs))
        self.iface.addToolBarIcon(self.view_logs)

        icon = QIcon(os.path.join(os.path.dirname(__file__), "qgeologis/img/timeseries.svg"))
        self.view_timeseries = QAction(icon, tr("View timeseries"), self.iface.mainWindow())
        self.view_timeseries.setCheckable(True)
        self.view_timeseries.triggered.connect(lambda: self.on_view_plots(self.view_timeseries))
        self.iface.addToolBarIcon(self.view_timeseries)

        self.import_config_action = QAction(tr("Import configuration"), self.iface.mainWindow())
        self.export_config_action = QAction(
            tr("Export configuration to ..."), self.iface.mainWindow()
        )
        self.import_config_action.triggered.connect(self.on_import_config)
        self.export_config_action.triggered.connect(self.on_export_config)
        self.iface.addPluginToMenu(u"QGeoloGIS", self.import_config_action)
        self.iface.addPluginToMenu(u"QGeoloGIS", self.export_config_action)

        QgsProject.instance().layerWillBeRemoved.connect(self.on_layer_removed)

    def on_layer_removed(self, layer_id):
        """ Remove layer configuration when the layer is removed

        :param layer_id: id of the layer
        :type layer_id: str
        """
        # Check if the layer is not part of the config,
        # in which case, it must be deleted from the config
        remove_layer_from_config(self.__config, layer_id)
        QgsProject.instance().writeEntry("QGeoloGIS", "config", json.dumps(self.__config))

        if self.__docks:
            self.view_logs.setChecked(False)
            self.view_timeseries.setChecked(False)
            self.view_logs.triggered.emit()
            self.view_timeseries.triggered.emit()

    def on_view_plots(self, plot_button):
        """ Open main QGeoloGIS dock

        :param plot_type: button reference
        :type plot_type: QAction
        """
        layer = self.iface.activeLayer()
        if not layer:
            plot_button.setChecked(False)
            return

        if layer.id() not in self.__config:
            if layer.geometryType() != QgsWkbTypes.NullGeometry:
                dlg = ConfigurePlotDialog(layer, self.iface.mainWindow())
                if dlg.exec_():
                    conf = dlg.config()
                    self.__config[layer.id()] = conf

                    json_config = json.dumps(self.__config)
                    QgsProject.instance().writeEntry("QGeoloGIS", "config", json_config)
                else:
                    plot_button.setChecked(False)
                    return
            else:
                plot_button.setChecked(False)
                return

        if plot_button.isChecked():
            if plot_button.text() == tr("View log plots"):
                plot_type = "logs"
                dock = QDockWidget(tr("Well Logs"))
            else:
                plot_type = "timeseries"
                dock = QDockWidget(tr("Timeseries"))

            dock.setObjectName("QGeoloGIS_plot_view_dock")
            dialog = MainDialog(dock, plot_type, self.__config, layer, self.iface)
            dialog.config_removed.connect(self.on_layer_removed)
            dock.setWidget(dialog)
            if len(self.__docks) == 0:
                self.iface.addDockWidget(Qt.LeftDockWidgetArea, dock)
            else:
                # not before 3.14, wait for new LTR
                # self.iface.addTabifiedDockWidget(Qt.LeftDockWidgetArea,dock,self.__docks)
                self.iface.mainWindow().tabifyDockWidget(self.__docks[-1], dock)
            self.__docks.append(dock)
        else:
            for dock in self.__docks:
                if dock.windowTitle() == tr("Well Logs") and plot_button.text() == tr(
                    "View log plots"
                ):
                    self.iface.removeDockWidget(dock)
                    dock.setParent(None)
                    rm_dock = dock
                elif dock.windowTitle() == tr("Timeseries") and plot_button.text() == tr(
                    "View timeseries"
                ):
                    self.iface.removeDockWidget(dock)
                    dock.setParent(None)
                    rm_dock = dock
            self.__docks.remove(rm_dock)

    def unload(self):
        """ Triggered when QGeologis is unloaded """
        QgsProject.instance().layerWillBeRemoved.disconnect(self.on_layer_removed)

        QgsProject.instance().readProject.disconnect(self.update_layer_config)
        QgsProject.instance().cleared.disconnect(self.update_layer_config)

        self.__tool = None
        self.__config = None
        if self.__docks:
            for dock in self.__docks:
                self.iface.removeDockWidget(dock)
                dock.setParent(None)

        self.iface.removeToolBarIcon(self.view_logs)
        self.iface.removeToolBarIcon(self.view_timeseries)

        self.view_logs.setParent(None)
        self.view_timeseries.setParent(None)

        self.iface.removePluginMenu(u"QGeoloGIS", self.import_config_action)
        self.iface.removePluginMenu(u"QGeoloGIS", self.export_config_action)
        self.import_config_action.setParent(None)
        self.export_config_action.setParent(None)

    def on_import_config(self):
        """ Triggered on import button """
        s = QSettings("Oslandia", "QGeoloGIS")
        last_dir = s.value("config_last_dir", None)
        if not last_dir:
            last_dir = os.path.dirname(__file__)

        dlg = QDialog(None)
        file_dialog = QFileDialog(
            None,
            tr("Choose a configuration file to import"),
            last_dir,
            "JSON files (*.json)",
            options=QFileDialog.DontUseNativeDialog,
            # transform into an embeddable QWidget
        )
        # when file dialog is done, close the main dialog
        file_dialog.finished.connect(dlg.done)
        overwrite_checkbox = QCheckBox(tr("Overwrite existing layers"))
        overwrite_checkbox.setChecked(True)
        vbox = QVBoxLayout()
        vbox.addWidget(file_dialog)
        vbox.addWidget(overwrite_checkbox)
        dlg.setLayout(vbox)

        r = dlg.exec_()
        if r == QDialog.Accepted:
            filename = file_dialog.selectedFiles()[0]
            s.setValue("config_last_dir", os.path.dirname(filename))
            self.__config = import_config(
                filename, overwrite_existing=overwrite_checkbox.isChecked()
            )
            QgsProject.instance().writeEntry("QGeoloGIS", "config", json.dumps(self.__config))

    def on_export_config(self):
        """ Triggered on export button """
        s = QSettings("Oslandia", "QGeoloGIS")
        last_dir = s.value("config_last_dir", None)
        if not last_dir:
            last_dir = os.path.dirname(__file__)

        filename, _ = QFileDialog.getSaveFileName(
            None, tr("Export the configuration to ..."), last_dir, "JSON files (*.json)"
        )
        if filename:
            s.setValue("config_last_dir", os.path.dirname(filename))
            export_config(self.__config, filename)

    def update_layer_config(self):
        """Open and parse the configuration file"""

        config, _ = QgsProject.instance().readEntry("QGeoloGIS", "config", "{}")
        self.__config = json.loads(config)
