#! python3  # noqa: E265

"""
   Plugin settings form integrated into QGIS 'Options' menu.
                                A QGIS plugin
FoliosWizard
                             -------------------
       begin                : 2023-08-20
       git sha              : $Format:%H$
       copyright            : (C) 2023 by Jean-Marie ARSAC
       email                : jmarsac@azimut.fr
***************************************************************************/

/***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/
"""

# standard
import os
import platform
from functools import partial
from pathlib import Path
from urllib.parse import quote

# PyQGIS
from qgis.core import Qgis, QgsApplication
from qgis.gui import QgsOptionsPageWidget, QgsOptionsWidgetFactory
from qgis.PyQt import uic
from qgis.PyQt.Qt import QUrl
from qgis.PyQt.QtGui import QDesktopServices, QIcon
from qgis.PyQt.QtWidgets import QFileDialog

# project
from folios_wizard.__about__ import (
    __icon_path__,
    __title__,
    __uri_homepage__,
    __uri_tracker__,
    __version__,
)
from folios_wizard.toolbelt import PlgLogger, PlgOptionsManager
from folios_wizard.toolbelt.preferences import PlgSettingsStructure

# ############################################################################
# ########## Globals ###############
# ##################################

FORM_CLASS, _ = uic.loadUiType(
    Path(__file__).parent / "{}.ui".format(Path(__file__).stem)
)


# ############################################################################
# ########## Classes ###############
# ##################################


class ConfigOptionsPage(FORM_CLASS, QgsOptionsPageWidget):
    """Settings form embedded into QGIS 'options' menu."""

    def __init__(self, parent):
        super().__init__(parent)
        self.log = PlgLogger().log
        self.plg_settings = PlgOptionsManager()

        # load UI and set objectName
        self.setupUi(self)
        self.setObjectName("mOptionsPage{}".format(__title__))

        report_context_message = quote(
            "> Reported from plugin settings\n\n"
            f"- operating system: {platform.system()} "
            f"{platform.release()}_{platform.version()}\n"
            f"- QGIS: {Qgis.QGIS_VERSION}"
            f"- plugin version: {__version__}\n"
        )

        # header
        self.lbl_title.setText(f"{__title__} - Version {__version__}")

        # customization
        self.btn_help.setIcon(QIcon(QgsApplication.iconPath("mActionHelpContents.svg")))
        self.btn_help.pressed.connect(
            partial(QDesktopServices.openUrl, QUrl(__uri_homepage__))
        )
        self.btn_report.setIcon(
            QIcon(QgsApplication.iconPath("console/iconSyntaxErrorConsole.svg"))
        )

        self.btn_report.pressed.connect(
            partial(
                QDesktopServices.openUrl,
                QUrl(
                    f"{__uri_tracker__}new?issuable_template=bug_report&"
                    "issue[title]=[BUG]&"
                    f"issue[description]={report_context_message}"
                ),
            )
        )

        self.btn_reset.setIcon(QIcon(QgsApplication.iconPath("mActionUndo.svg")))
        self.btn_reset.pressed.connect(self.reset_settings)
        self.toolButton_maps_output_folder.pressed.connect(
            lambda: self.showDialogConfig(self.lineEdit_maps_output_folder)
        )
        self.toolButton_maps_templates_folder.pressed.connect(
            lambda: self.showDialogConfig(
                self.lineEdit_maps_templates_folder,
                suggested_dir=os.path.join(
                    QgsApplication.qgisSettingsDirPath(), "composer_templates"
                ),
            )
        )

        # load previously saved settings
        self.load_settings()

    def apply(self):
        """Called to permanently apply the settings shown in the options page (e.g. \
        save them to QgsSettings objects). This is usually called when the options \
        dialog is accepted."""
        settings = self.plg_settings.get_plg_settings()

        # misc
        settings.debug_mode = self.opt_debug.isChecked()
        settings.version = __version__
        settings.maps_output_folder = self.lineEdit_maps_output_folder.text()
        settings.maps_templates_folder = self.lineEdit_maps_templates_folder.text()
        settings.maps_prefix = self.lineEdit_maps_prefix.text()
        settings.maps_suffix = self.lineEdit_maps_suffix.text()

        settings.maps_scales = self.lineEdit_maps_scales.text()

        settings.title = self.lineEdit_title.text()
        settings.subtitle = self.lineEdit_subtitle.text()
        settings.description = self.lineEdit_description.text()
        settings.field1 = self.lineEdit_field1.text()
        settings.field2 = self.lineEdit_field2.text()
        settings.field3 = self.lineEdit_field3.text()
        settings.field4 = self.lineEdit_field4.text()
        # dump new settings into QgsSettings
        self.plg_settings.save_from_object(settings)

        if __debug__:
            self.log(
                message="DEBUG - Settings successfully saved.",
                log_level=4,
            )

    def load_settings(self):
        """Load options from QgsSettings into UI form."""
        settings = self.plg_settings.get_plg_settings()

        # global
        self.opt_debug.setChecked(settings.debug_mode)
        self.lbl_version_saved_value.setText(settings.version)
        self.lineEdit_maps_prefix.setText(settings.maps_prefix)
        self.lineEdit_maps_suffix.setText(settings.maps_suffix)

        self.lineEdit_maps_output_folder.setText(
            settings.maps_output_folder,
        )
        self.lineEdit_maps_templates_folder.setText(
            settings.maps_templates_folder,
        )
        self.lineEdit_maps_scales.setText(settings.maps_scales)
        self.lineEdit_title.setText(settings.title)
        self.lineEdit_subtitle.setText(settings.subtitle)
        self.lineEdit_description.setText(settings.description)
        self.lineEdit_field1.setText(settings.field1)
        self.lineEdit_field2.setText(settings.field2)
        self.lineEdit_field3.setText(settings.field3)
        self.lineEdit_field4.setText(settings.field4)

    def reset_settings(self):
        """Reset settings to default values (set in preferences.py module)."""
        default_settings = PlgSettingsStructure()

        # dump default settings into QgsSettings
        self.plg_settings.save_from_object(default_settings)

        # update the form
        self.load_settings()

    def showDialogConfig(self, obj, suggested_dir: str = "", flags="Directory"):
        if flags == "Directory":
            fname = QFileDialog.getExistingDirectory(self, directory=suggested_dir)
        elif flags == "Executable":
            fname, _ = QFileDialog.getOpenFileName(self, directory=suggested_dir)
        else:
            return

        if fname:
            obj.setText(fname)


class PlgOptionsFactory(QgsOptionsWidgetFactory):
    """Factory for options widget."""

    def __init__(self):
        """Constructor."""
        super().__init__()

    def icon(self) -> QIcon:
        """Returns plugin icon, used to as tab icon in QGIS options tab widget.

        :return: _description_
        :rtype: QIcon
        """
        return QIcon(str(__icon_path__))

    def createWidget(self, parent) -> ConfigOptionsPage:
        """Create settings widget.

        :param parent: Qt parent where to include the options page.
        :type parent: QObject

        :return: options page for tab widget
        :rtype: ConfigOptionsPage
        """
        return ConfigOptionsPage(parent)

    def title(self) -> str:
        """Returns plugin title, used to name the tab in QGIS options tab widget.

        :return: plugin title from about module
        :rtype: str
        """
        return __title__

    def helpId(self) -> str:
        """Returns plugin help URL.

        :return: plugin homepage url from about module
        :rtype: str
        """
        return __uri_homepage__
