import importlib
import os
import traceback

from qgis.PyQt.QtCore import QObject, pyqtSignal
from qgis.PyQt.QtGui import QIcon, QStandardItem
from qgis.PyQt.QtWidgets import QMenu
from qgis.utils import plugins

from ..compat import MESSAGE_LEVEL_CRITICAL, USER_ROLE
from .path_utilities import parse_posix_path
from .settings import Settings

# Try to load these plugin names in priority order
NAMES = ["riverscapes_viewer_dev", "riverscapes_viewer"]


class QRaveIntegration(QObject):
    qrave_to_qris = pyqtSignal(str, str, dict)

    def __init__(self, parent):
        super().__init__(parent)
        self.name = None
        self.plugin_instance = None
        self.symbology_folders = None
        self.qrave_map_layer = None
        self.protocol_folder = None
        self.RemoteProject = None
        self.telemetry = None
        self.BaseMaps = None
        self.ProjectUploadDialog = None

        try:
            # from https://gis.stackexchange.com/questions/403501/using-qgis-plugin-from-another-plugin

            # Attemp to find RAVE plugin using lower case names
            plugins_lower_case = {k.lower(): k for k in plugins.keys()}
            rave_names_lower_case = [name.lower() for name in NAMES]
            matched_lower_case_name = next((pname for pname in rave_names_lower_case if pname in plugins_lower_case), None)
            if matched_lower_case_name is not None:
                self.name = plugins_lower_case[matched_lower_case_name]
                self.plugin_instance = plugins[self.name]
                self.qrave_map_layer = importlib.import_module(f"{self.name}.src.classes.qrave_map_layer")
                try:
                    remote_project_module = importlib.import_module(f"{self.name}.src.classes.remote_project")
                    self.RemoteProject = remote_project_module.RemoteProject
                except ImportError:
                    self.RemoteProject = None
                try:
                    telemetry_module = importlib.import_module(f"{self.name}.src.classes.telemetry")
                    self.telemetry = telemetry_module.Telemetry("QRiS", Settings().version())
                except ImportError:
                    self.telemetry = None

                self.symbology_folders = [parse_posix_path(os.path.join(self.qrave_map_layer.SYMBOLOGY_DIR, "RiverscapesStudio")), parse_posix_path(os.path.join(self.qrave_map_layer.SYMBOLOGY_DIR, "Shared"))]

                self.resources_folder = parse_posix_path(os.path.join(self.qrave_map_layer.SYMBOLOGY_DIR, ".."))
                self.protocol_folder = parse_posix_path(os.path.join(self.resources_folder, "QRiS", "protocols"))
                self.climate_engine_json = parse_posix_path(os.path.join(self.resources_folder, "QRiS", "climate_engine_datasets.json"))

                # TODO: Currently in locally deployed qris folder, change these paths when we make the changeover.
                local_qris_resources = parse_posix_path(os.path.join(os.path.dirname(__file__), "..", "..", "resources"))
                self.lookups_json = parse_posix_path(os.path.join(local_qris_resources, "lookups.json"))
                # self.lookups_json = parse_posix_path(os.path.join(self.resources_folder, 'lookups.json'))

                self.basemaps_module = importlib.import_module(f"{self.name}.src.classes.basemaps")
                self.ProjectTreeData = self.qrave_map_layer.ProjectTreeData
                self.QRaveBaseMap = self.basemaps_module.QRaveBaseMap
                self.BaseMaps = self.basemaps_module.BaseMaps()
                self.BaseMaps.load()

                # Uploader
                self.riverscapes_project_module = importlib.import_module(f"{self.name}.src.classes.project")
                self.project_upload_module = importlib.import_module(f"{self.name}.src.project_upload_dialog")
                self.ProjectUploadDialog = self.project_upload_module.ProjectUploadDialog

                # Successfully loaded the plugin, log a message
                Settings().log(f"Riverscapes Viewer plugin '{self.name}' loaded successfully.")

                if self.plugin_instance.dockwidget:
                    # Check if the signal is already connected
                    if self.plugin_instance.dockwidget.receivers(self.plugin_instance.dockwidget.layerMenuOpen) > 0:
                        self.plugin_instance.dockwidget.layerMenuOpen.disconnect()
                    self.plugin_instance.dockwidget.layerMenuOpen.connect(self.qrave_add_to_map_menu_item)

        except Exception as ex:
            Settings().log(f"Error initializing QRaveIntegration: {ex!s}\n{traceback.format_exc()}", MESSAGE_LEVEL_CRITICAL)
            self.name = None
            self.plugin_instance = None
            self.symbology_folders = None
            self.qrave_map_layer = None
            self.protocol_folder = None
            self.BaseMaps = None

    def qrave_add_to_map_menu_item(self, menu: QMenu, item: QStandardItem, data):
        """Custom menu to show at the bottom of the QRave context menu

        Args:
            menu (_type_): ContextMenu(QMenu) object from QRave
            item (QStandardItem): QStandardItem (PyQt)
            data (ProjectTreeData): ProjectTreeData (QRave)
        """

        if self.RemoteProject and isinstance(data.project, self.RemoteProject):
            return  # Do not add menu for remote projects

        menu.addSeparator()
        menu.addCustomAction(QIcon(":/plugins/qris_toolbar/add_to_map"), "Add to QRiS", lambda: self.add_to_qris(item, data))

    def add_to_qris(self, item: QStandardItem, data):
        """_summary_

        Args:
            item (QStandardItem): QStandardItem (PyQt)
            data (ProjectTreeData): ProjectTreeData (QRave)
        """

        layer = item.data(USER_ROLE).data
        qrave_project = data.project
        project_meta = qrave_project.meta

        project_source_url = ("None", "string")
        if qrave_project.warehouse_meta is not None:
            project_id = qrave_project.warehouse_meta.get("id", None)
            if project_id is not None:
                project_source_url = f"https://data.riverscapes.net/p/{project_id[0]}"

        project_meta["SourceUrl"] = (project_source_url, "string")

        layer_meta = data.data.meta
        out_meta = {"layer_label": layer.label, "project_metadata": project_meta, "layer_metadata": layer_meta}
        proj_type = data.project.project_type
        symbology = layer.bl_attr.get("symbology", None)
        if symbology is not None:
            out_meta["symbology"] = os.path.join(proj_type, symbology)
        layer_uri = layer.layer_uri.lower()
        if layer.layer_type == "raster":
            path = layer.layer_uri
        # check if the layer is a shapefile
        elif layer_uri.endswith(".shp"):
            path = layer.layer_uri
        else:
            path = f"{layer.layer_uri}|layername={layer.layer_name}"
        self.qrave_to_qris.emit(path, layer.layer_type, out_meta)
