"""
Different parameter do create the provider needed to access the R language installed for Movecost tool analyses
This provider was created using as a base the plugin Processing R Provider created by Victor Olaya in 2012
"""
# -*- coding: utf-8 -*-
import os
import shutil

from processing.core.ProcessingConfig import ProcessingConfig, Setting
from processing.gui.ProviderActions import ProviderActions
from processing.gui.ProcessingToolbox import ProcessingToolbox
from qgis.utils import iface
from qgis.core import Qgis, QgsMessageLog, QgsProcessingProvider, QgsApplication
from qgis.PyQt.QtCore import QCoreApplication, QSettings
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QWidget, QAction

from .Utils import ParamsR, plugin_version
from .processing.create_new_script import CreateNewScriptAction
from .processing.delete_script import DeleteScriptAction
from .processing.edit_script import EditScriptAction
from .processing.algorithm import RAlgorithm
from .processing.exceptions import InvalidScriptException


class SiliciteR(QgsProcessingProvider):
    """Processing provider for executing R scripts"""

    def __init__(self):
        super().__init__()
        self.algs = []
        self.actions = []
        create_script_action = CreateNewScriptAction()
        self.actions.append(create_script_action)
        self.contextMenuActions = [EditScriptAction(), DeleteScriptAction()]

        self.r_version = None
    

    def refreshAlgorithms(self):
        super().refreshAlgorithms()


    def load(self):
        """
        Called when first loading provider

        :returns: True (if no problems)
        :rtype: bool
        """
        ProcessingConfig.settingIcons[self.name()] = self.icon()

        """Verification if Processing R Provider is installed to get possible already completed parameters"""
        profile_home = QgsApplication.qgisSettingsDirPath()
        processingR = os.path.exists(os.path.join(profile_home, 'python', 'plugins', 'processing_r'))
        # First step, does the plugin Processing R Provider is installed ?
        prp = False
        try:
            if processingR:
                from processing_r.processing.utils import RUtils
                # Second step, does the plugin is activated to access the parameters
                if ProcessingConfig.getSetting(RUtils.R_FOLDER) is not None:
                    prp = True
        except Exception:
            pass


        """Preparation of the different parameters"""
        scripts = ParamsR.default_scripts_folder()
        # print("A (Dossiers scripts) :",scripts) # debugtest
        ProcessingConfig.addSetting(
            Setting(
                self.name(),
                ParamsR.DOSSIER_SCRIPTS_R,
                SiliciteR.tr("Dossier contenant les scripts R"),
                scripts,
                valuetype=Setting.MULTIPLE_FOLDERS,
            )
        )
        QSettings().setValue("Siligites/DOSSIER_SCRIPTS_R", scripts)
        
        user_choice = bool(ParamsR.user_libs())
        ProcessingConfig.addSetting(
            Setting(
                self.name(), 
                ParamsR.USER_LIB, 
                SiliciteR.tr("Utiliser des librairies déjà installées sur l'ordinateur"), 
                user_choice,
            )
        )
        QSettings().setValue("Siligites/USER_LIB", user_choice)

        libs = ParamsR.r_library_folder()
        # print("B (Dossier librairies) :",libs) # debugtest
        ProcessingConfig.addSetting(
            Setting(
                self.name(),
                ParamsR.LIBS_R,
                SiliciteR.tr("Dossier des librairies à utiliser"),
                libs,
                valuetype=Setting.FOLDER,
            )
        )
        QSettings().setValue("Siligites/LIBS_R", libs)
        
        repository = ParamsR.repository()
        ProcessingConfig.addSetting(
            Setting(
                self.name(),
                ParamsR.DEPOT_R,
                SiliciteR.tr("Répertoire des packages et librairies"),
                repository,
                valuetype=Setting.STRING,
            )
        )
        QSettings().setValue("Siligites/DEPOT_R", repository)

        folder = ParamsR.r_binary_folder()
        # print("C (Dossier R) :",folder) # debugtest
        ProcessingConfig.addSetting(
            Setting(
                self.name(), 
                ParamsR.DOSSIER_R, 
                SiliciteR.tr("Dossier contenant R"), 
                folder, 
                valuetype=Setting.FOLDER
            )
        )
        QSettings().setValue("Siligites/DOSSIER_R", folder)

        choice = bool(ParamsR.R_64())
        if ParamsR.is_windows():
            ProcessingConfig.addSetting(
                Setting(
                    self.name(), 
                    ParamsR.R64, 
                    SiliciteR.tr("Utiliser la version 64bits de Windows"), 
                    choice,
                )
            )
            if choice not in ['', None]:
                QSettings().setValue("Siligites/R64", choice)

        ProviderActions.registerProviderActions(self, self.actions)
        ProcessingConfig.readSettings()
        self.refreshAlgorithms()
        
        """Verification if theirs no problems with the integration of the paths"""
        parameters = [ParamsR.DOSSIER_SCRIPTS_R,
                      ParamsR.USER_LIB,
                      ParamsR.LIBS_R,
                      ParamsR.DEPOT_R,
                      ParamsR.DOSSIER_R,
                      ParamsR.R64
                      ]
        results = [scripts,
                   ProcessingConfig.getSetting(RUtils.R_USE_USER_LIB) if prp else True,
                   libs,
                   ProcessingConfig.getSetting(RUtils.R_REPO) if prp else "http://cran.at.r-project.org/",
                   folder,
                   ProcessingConfig.getSetting(RUtils.R_USE64) if prp else (True if ParamsR.is_windows() else False)
                   ]
        for n in range(0, len(parameters)):
            if ProcessingConfig.getSetting(parameters[n]) != results[n]:
                ProcessingConfig.setSettingValue(parameters[n], results[n])
                ProcessingConfig.readSettings()
                self.refreshAlgorithms()

        """Copy of the scripts"""
        # Access to the folder where R scripts are stored in the module
        source_profile = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'rscripts')
        # print(source_profile) # debugtest

        # Access to the folder where they must be copied to make the module work
        scripts = ProcessingConfig.getSetting(ParamsR.DOSSIER_SCRIPTS_R)
        # print(rs) # debugtest

        # Check that the file exists
        if not os.path.exists(scripts):
            os.makedirs(scripts)

        # Files are copied at the time of use, allowing them to be updated automatically in the event of changes
        for filename in os.listdir(source_profile):
            if ".rsx" in str(filename):
                # print(str(filename)) # debugtest
                source_file = os.path.join(source_profile, filename)
                dest_file = os.path.join(scripts, filename)
                # print(dest_file) # debugtest

                shutil.copy2(source_file, dest_file)
        # print(os.listdir(scripts)) # debugtest

        for provider in QgsApplication.processingRegistry().providers():
            provider.refreshAlgorithms()
        
        self.r_version = ParamsR.get_r_version()
        return True


    def unload(self):
        """
        Called when unloading provider
        """
        ProcessingConfig.removeSetting(ParamsR.DOSSIER_SCRIPTS_R)
        ProcessingConfig.removeSetting(ParamsR.USER_LIB)
        ProcessingConfig.removeSetting(ParamsR.LIBS_R)
        ProcessingConfig.removeSetting(ParamsR.DEPOT_R)
        ProcessingConfig.removeSetting(ParamsR.DOSSIER_R)
        if ParamsR.is_windows():
            ProcessingConfig.removeSetting(ParamsR.R64)
        ProviderActions.deregisterProviderActions(self)
        #ProviderContextMenuActions.deregisterProviderContextMenuActions(self.contextMenuActions)


    def initAlgorithm(self, _=None):
        """
        Initializes the algorithm
        """
        pass


    def loadAlgorithms(self):
        """
        Called when provider must populate its available algorithms
        """
        algs = []
        for f in ParamsR.script_folders():
            algs.extend(self.load_scripts_from_folder(f))

        for a in algs:
            self.addAlgorithm(a)


    def load_scripts_from_folder(self, folder):
        """
        Loads all scripts found under the specified sub-folder

        :param folder: Folder of the scripts
        :type string: str

        :returns: Algorithms identified
        :rtype: list
        """
        if not os.path.exists(folder):
            return []
        # Check and copy all R scripts implemented in the extension
        algs = []
        for path, _, files in os.walk(folder):
            for description_file in files:
                if description_file.lower().endswith("rsx"):
                    try:
                        fullpath = os.path.join(path, description_file)
                        alg = RAlgorithm(fullpath)
                        if alg.name().strip():
                            algs.append(alg)
                    except InvalidScriptException as e:
                        QgsMessageLog.logMessage(e.msg, SiliciteR.tr("Processing"), Qgis.MessageLevel.Critical)
                    except Exception as e:  # pylint: disable=broad-except
                        log = "\n".join([SiliciteR.tr("Impossible de charger le script R"),
                                         description_file,
                                         str(e)
                            ])
                        QgsMessageLog.logMessage(
                            log,
                            SiliciteR.tr("Processing"),
                            Qgis.MessageLevel.Critical,
                        )
        return algs


    def icon(self):
        """
        Returns the provider's icon

        :returns: Icon of the provider
        :rtype: QIcon
        """
        path = os.path.join(os.path.dirname(__file__), "..", "icon.png")
        if not os.path.exists(path):
            return ""
        return QIcon(path)


    def name(self):
        """
        Display name for provider

        :returns: Name of the provider
        :rtype: str
        """
        return "SiliciteR"


    def versionInfo(self):
        """
        Provider plugin version

        :returns: Version de R utilisée
        :rtype: float
        """
        if not self.r_version:
            return plugin_version()

        return plugin_version()


    def id(self):
        """
        Unique ID for provider

        :returns: Identificator of the provider
        :rtype: str
        """
        return "siliciter"

    @staticmethod
    def tr(string):
        return QCoreApplication.translate("SiliciteR", string)


    def supportedOutputTableExtensions(self):
        """
        Extensions for non-spatial vector outputs

        :returns: Extension of the outputs
        :rtype: list
        """
        return ["csv"]


    def defaultVectorFileExtension(self, hasGeometry=True):
        """
        Default extension -- we use Geopackage for spatial layers, CSV for non-spatial layers
        
        :param hasGeometry: Does the element has a geometry
        :type hasGeometry: bool

        :returns: Extension of the outputs
        :rtype: str
        """
        return "gpkg" if hasGeometry else "csv"


    def supportsNonFileBasedOutput(self):
        """
        Provider cannot handle memory layers/db sources

        :returns: False
        :rtype: bool
        """
        return False

