#! python3  # noqa: E265

"""
Plugin settings form integrated into QGIS 'Options' menu.
"""

# PyQGIS


import os

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

import yaml

# 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 yaml.loader import SafeLoader

# project
from topaze.__about__ import (
    DIR_PLUGIN_ROOT,
    __icon_path__,
    __title__,
    __uri_homepage__,
    __uri_tracker__,
    __version__,
)
from topaze.dlg_util import DlgUtil
from topaze.gui.edit_topaze_config_file_dialog import EditTopazeConfigFileDialog
from topaze.toolbelt import PlgLogger, PlgOptionsManager
from topaze.toolbelt.preferences import PlgSettingsStructure
from topaze.topaze_config import TopazeConfig

# ############################################################################
# ########## 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.clicked.connect(
            partial(QDesktopServices.openUrl, QUrl(__uri_homepage__))
        )

        self.btn_report.setIcon(
            QIcon(QgsApplication.iconPath("console/iconSyntaxErrorConsole.svg"))
        )

        self.btn_report.clicked.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.clicked.connect(self.reset_settings)

        self.pushButton_browseForConfigfile.clicked.connect(self.browseForConfigFile)
        self.lineEdit_config_file.textChanged.connect(self.config_file_changed)
        # load previously saved settings
        self.load_settings()

        self.pushButton_edit_topaze_config_file.clicked.connect(
            self.edit_topaze_config_file
        )

    def edit_topaze_config_file(self):
        dlg_edit_topaze_config_file = EditTopazeConfigFileDialog(
            config_path=self.lineEdit_config_file.text()
        )
        dlg_edit_topaze_config_file.exec_()

    def browseForConfigFile(self):
        settings = self.plg_settings.get_plg_settings()
        if os.path.exists(os.path.dirname(settings.config_file)):
            start_in = os.path.dirname(settings.config_file)
        else:
            start_in = os.path.join(DIR_PLUGIN_ROOT, "resources/settings")
        DlgUtil.showDialogConfig(
            self.lineEdit_config_file,
            flag="File",
            start_dir=start_in,
            prompt="Select configuration file",
            filter="Config (*.yml)",
        )

    def config_file_changed(self):
        print("config_file_changed")
        try:
            with open(self.lineEdit_config_file.text()) as f:
                config_dict = yaml.load(f, Loader=SafeLoader)[0]["topaze"]
        except Exception as e:
            print(str(e))

    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.config_file = self.lineEdit_config_file.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_config_file.setText(settings.config_file)

    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()


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__
