# -*- coding: utf-8 -*-

__author__ = '(C) 2023 by Gerald Kogler'
__date__ = '1/10/2023'
__copyright__ = 'Copyright 2023, 300.000 Km/s'
__license__ = 'GPLv3 license'

import os.path
import webbrowser

from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication, QUrl
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction, QDialogButtonBox, QPushButton, QMenu

from qgis.core import QgsProject, Qgis, QgsApplication
from qgis.gui import QgisInterface

# Initialize Qt resources from file resources.py
from .resources import *
# Import the code for the dialog
from .qwv_dialog1 import QWVDialog1
from .qwv_dialog2 import QWVDialog2
from .qwv_dialog3 import QWVDialog3
from .map_store import mapStoreHandler
from .utils import Utils
from processing_provider.provider import Provider

# parameters for internal use
_writeMbtiles = True                # deactivate for testing writing of mapset confs
_deactivateSFTP = False              # SFTP actually doesn't work in some cases (for example when QGIS is installed from flatpak), so for now we leave it deactivated
_mbtilesOgr2ogr = True              # False for using QGIS vector tile writer
_removeGpkgs = True                 # False for leaving temporarly created GPKS in folder
_writeMaplibreStylesFile = False    # addionally write Maplibre JSON file, which then can be used directly in QGIS to apply styles to mbtiles layers
_printLog = False                   # print some basic parameters to python console


class QuickWebViewerPlugin:
    """QGIS Plugin Implementation."""

    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        self.provider = None
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n',
            'QuickWebViewer_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        icon_path = os.path.join(self.plugin_dir, 'resources/icons/icon.svg')
        self.menu = QMenu(Utils.tr('QuickWebViewer'))
        self.menu.setIcon(QIcon(icon_path))
        self.toolbar = self.iface.addToolBar(Utils.tr('QuickWebViewer'))
        self.toolbar.setObjectName(Utils.tr('QuickWebViewer'))

        # need workaround for WebMenu
        _temp_act = QAction('temp', self.iface.mainWindow())
        self.iface.addPluginToWebMenu("_tmp", _temp_act)
        self.iface.webMenu().addMenu(self.menu)
        self.iface.removePluginWebMenu("_tmp", _temp_act)

        # Check if plugin was started the first time in current QGIS session
        # Must be set in initGui() to survive plugin reloads
        self.first_start1 = None
        self.first_start2 = None
        self.first_start3 = None

        self.pluginVersion = "0.4"
        if _printLog:
            print("init", self.pluginVersion)

        # read plugin settings when new project is loaded
        self.dlg1 = None
        self.dlg2 = None
        self.dlg3 = None
        self.mapStoreHandler = None
        QgsProject.instance().readProject.disconnect()
        QgsProject.instance().readProject.connect(self.readPluginSettings)
        #QgsProject.instance().mapThemeCollectionChanged.connect(self.readPluginSettings)

        # read settings from QGIS project on "Plugin Reload"
        if (QgsProject.instance().fileName() != ""):
            self.mapStoreHandler = mapStoreHandler(self, _printLog)
            self.mapStoreHandler.readSettingsFromProject()


    def readPluginSettings(self):
        """mapStoreHandler to load/save plugin variables to QGIS project."""

        self.mapStoreHandler = mapStoreHandler(self, _printLog)
        self.mapStoreHandler.readSettingsFromProject()

        self.initDialog(1)
        self.initDialog(2)
        self.initDialog(3)


    def initDialog(self, step):
        """Create GUI for dialog1."""

        if step < 1 or step > 3:
            return False

        if step == 1:
            self.dlg1 = QWVDialog1(self.iface, self.iface.mainWindow(), _printLog)

            if self.mapStoreHandler:
                self.mapStoreHandler.readSettingsFromProject(1)
            self.dlg1.button_box.helpRequested.connect(self.help1)

            self.dlg1.saveBtn.clicked.connect(lambda:self.mapStoreHandler.writeSettingsToProject(1, self.dlg1.messageBar))
            self.dlg1.closeBtn.clicked.connect(lambda:self.dlg1.hide())
            self.dlg1.runBtn.clicked.connect(lambda:self.runProcess1())

        elif step == 2:
            self.dlg2 = QWVDialog2(self.iface, self.iface.mainWindow())

            if self.mapStoreHandler:
                self.mapStoreHandler.readSettingsFromProject(2)
            self.dlg2.button_box.helpRequested.connect(self.help2)

            self.dlg2.saveBtn.clicked.connect(lambda:self.mapStoreHandler.writeSettingsToProject(2, self.dlg2.messageBar))
            self.dlg2.closeBtn.clicked.connect(lambda:self.dlg2.hide())
            self.dlg2.runBtn.clicked.connect(lambda:self.runProcess2())

        elif step == 3:
            self.dlg3 = QWVDialog3(self.iface, self.iface.mainWindow(), _deactivateSFTP)

            if self.mapStoreHandler:
                self.mapStoreHandler.readSettingsFromProject(3)
            self.dlg3.button_box.helpRequested.connect(self.help3)

            self.dlg3.saveBtn.clicked.connect(lambda:self.mapStoreHandler.writeSettingsToProject(3, self.dlg3.messageBar))
            self.dlg3.closeBtn.clicked.connect(lambda:self.dlg3.hide())
            self.dlg3.runBtn.clicked.connect(lambda:self.runProcess3())


    def add_action(
        self,
        icon_path,
        text,
        callback,
        enabled_flag=True,
        add_to_menu=True,
        add_to_toolbar=True,
        status_tip=None,
        whats_this=None,
        parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToWebMenu(
                self.menu.title(),
                action)

        self.actions.append(action)

        return action


    def initProcessing(self):
        self.provider = Provider()
        QgsApplication.processingRegistry().addProvider(self.provider)


    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        self.initProcessing()

        icon_path = os.path.join(os.path.dirname(__file__), "resources/icons")
        self.add_action(
            os.path.join(icon_path, "icon_1.svg"),
            text=Utils.tr('1. Export mapset'),
            callback=lambda:self.run(1),
            parent=self.iface.mainWindow())
        self.add_action(
            os.path.join(icon_path, "icon_2.svg"),
            text=Utils.tr('2. Export viewer'),
            callback=lambda:self.run(2),
            parent=self.iface.mainWindow())
        self.add_action(
            os.path.join(icon_path, "icon_3.svg"),
            text=Utils.tr('3. Publish viewer'),
            callback=lambda:self.run(3),
            parent=self.iface.mainWindow())
        self.add_action(
            os.path.join(icon_path, "help.svg"),
            text=Utils.tr('Help'),
            callback=self.help0,
            parent=self.iface.mainWindow(),
            add_to_toolbar=False)

        self.toolbar.setVisible(True)

        # will be set False in run()
        self.first_start1 = True
        self.first_start2 = True
        self.first_start3 = True


    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        QgsApplication.processingRegistry().removeProvider(self.provider)

        for action in self.actions:
            self.iface.removePluginWebMenu(self.menu.title(), action)

        # remove the toolbar
        if self.toolbar:
            del self.toolbar

        if self.menu:
            self.iface.webMenu().removeAction(self.menu.menuAction())
            self.iface.addLayerMenu().removeAction(self.menu.menuAction())


    def help(self, anchor=""):
        '''Display a help page'''
        url = "https://gitlab.com/300000-kms/QuickWebViewer/" + anchor
        webbrowser.open(url, new=2)

    def help0(self):
        self.help()

    def help1(self):
        self.help("#export_mapset")

    def help2(self):
        self.help("#export_viewer")

    def help3(self):
        self.help("#publish_viewer")


    def run(self, step):
        """Run method that performs all the real work"""

        if (QgsProject.instance().fileName() == ""):
            self.iface.messageBar().pushMessage(Utils.tr("Warning"), Utils.tr("Please open a project file in order to use this plugin"), level=Qgis.Warning, duration=3)
            return False

        if step == 1:
            # open dialog 1
            if self.first_start1 == True:
                self.first_start1 = False
                self.initDialog(1)

            self.dlg1.show()
            self.mapStoreHandler.loadViews()
            result = self.dlg1.exec_()

        elif step == 2:
            # open dialog 2
            if self.first_start2 == True:
                self.first_start2 = False
                self.initDialog(2)

            self.dlg2.show()
            self.dlg2.loadMapsets()
            result = self.dlg2.exec_()

        elif step == 3:
            # open dialog 3
            if self.first_start3 == True:
                self.first_start3 = False
                self.initDialog(3)

            self.dlg3.show()
            result = self.dlg3.exec_()

        else:
            return False


    def runProcess1(self):
        """Run method for exporting mapsets"""
        
        # save settings of none saved
        if self.mapStoreHandler.pluginSettings == None:
            self.mapStoreHandler.writeSettingsToProject(1, self.dlg1.messageBar)

        # minimum filled out form elements to proceed
        if self.dlg1.dialog1_name.text() != "" and self.dlg1.dialog1_views.rowCount() > 0 and len(self.dlg1.dialog1_views.layers) > 0 and self.dlg1.dialog1_views.layers[0] != None:

            if Utils.isValidExtentField(self.dlg1.dialog1_extent.text()):
                # export mapset
                self.dlg1.updateViewsAndLayerData()
                mapsetPath = self.mapStoreHandler.makeExportFolder()
                self.mapStoreHandler.writeMapsetJson(mapsetPath, Utils.toAsciiAlnum(self.dlg1.dialog1_name.text()), _writeMaplibreStylesFile)
                if _writeMbtiles:
                    self.dlg1.exportMbtiles(mapsetPath, _mbtilesOgr2ogr, _removeGpkgs)

                self.dlg1.messageBar.pushMessage(Utils.tr("Success"), Utils.tr("Mapset and mbtiles written successfully."), level=Qgis.Success, duration=3)
            else:
                self.dlg1.messageBar.pushMessage(Utils.tr("Warning"), Utils.tr("You have to fill the extent in the right format."), level=Qgis.Warning, duration=3)

        else:
            self.dlg1.messageBar.pushMessage(Utils.tr("Warning"), Utils.tr("You have to select at least one view with one layer and the mapset name in order to proceed."), level=Qgis.Warning, duration=3)


    def runProcess2(self):
        """Run method for exporting viewer"""
        
        # save settings of none saved
        if self.mapStoreHandler.pluginSettings == None:
            self.mapStoreHandler.writeSettingsToProject(2, self.dlg2.messageBar)

        # minimum filled out form elements to proceed
        if len(self.dlg2.dialog2_mapsets_list) > 0 and self.dlg2.isMapsetChecked():

            # export viewer
            self.mapStoreHandler.writeViewerJson(self.dlg2.dialog2_mapsets_list)
            self.dlg2.setupResources()

            self.dlg2.messageBar.pushMessage(Utils.tr("Success"), Utils.tr("Viewer exported successfully."), level=Qgis.Success, duration=3)
        else:
            self.dlg2.messageBar.pushMessage(Utils.tr("Warning"), Utils.tr("You have to define the Mapset Folder and select one mapset to proceed."), level=Qgis.Warning, duration=3)


    def runProcess3(self):
        """Run method for publishing viewer"""
        
        # save settings of none saved
        if self.mapStoreHandler.pluginSettings == None:
            self.mapStoreHandler.writeSettingsToProject(3, self.dlg3.messageBar)

        # publish viewer
        if self.dlg3.connectToServer(True):
            self.dlg3.messageBar.pushMessage(Utils.tr("Success"), Utils.tr("Viewer published successfully."), level=Qgis.Success, duration=3)
