import os

from openlog.datamodel.connection.spatialite.spatialite_connection import (
    SpatialiteConnection,
)
from openlog.plugins.hookspecs import ConnectionHook, hookimpl
from openlog.toolbelt.log_handler import PlgLogger

#: Name of the plugin that will be referenced in our configuration
PLUGIN_NAME = "Spatialite"
BASE_SETTINGS_KEY = "/OpenLog/plugin"
RECENT_SPATIALITE_KEY = "/recent_spatialite"
NB_RECENT_SPATIALITE = 5

# PyQGIS
from qgis.core import QgsApplication, QgsSettings
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction, QFileDialog, QMenu

# project
from openlog.__about__ import DIR_PLUGIN_ROOT


# function returned by ConnectionHook : spatialite menu -> [Open..., recent .db files]
def spatialite_menu(openlog) -> QMenu:
    """
    Function called from plugin manager.
    Args:
        - parent : mainWindow
        - openlog : OpenlogPlugin instance
    """

    def _get_recent_spatialite_files() -> list:
        """
        Function transforming result in a list.
        """
        recent_spatialite = settings.value(BASE_SETTINGS_KEY + RECENT_SPATIALITE_KEY)
        if recent_spatialite is None or recent_spatialite == "":
            recent_spatialite = []
        elif isinstance(recent_spatialite, str):
            recent_spatialite = [recent_spatialite]

        return recent_spatialite

    # internal functions
    # functions to handle action triggered signal and add recent spatialite connections to menu
    def _open_spatialite_file(filename):
        # if filename doesn't exist, remove from settings
        if not os.path.exists(filename):
            settings = QgsSettings()
            recent_spatialite = _get_recent_spatialite_files()
            if isinstance(recent_spatialite, list) and filename in recent_spatialite:
                recent_spatialite.pop(recent_spatialite.index(filename))
                settings.setValue(
                    BASE_SETTINGS_KEY + RECENT_SPATIALITE_KEY, recent_spatialite
                )
            log = PlgLogger().log
            log(message=f"File {filename} doesn't exist", log_level=1, push=True)
            return

        connection = SpatialiteConnection(filename, new_file=False)
        openlog._define_current_connection(connection)
        # Add new file to recent file
        settings = QgsSettings()
        recent_spatialite = _get_recent_spatialite_files()
        # Insert new file
        if recent_spatialite is None or recent_spatialite == "":
            recent_spatialite = []
        elif isinstance(recent_spatialite, str):
            recent_spatialite = [recent_spatialite]
        recent_spatialite.insert(0, filename)

        def unique(sequence):
            seen = set()
            return [x for x in sequence if not (x in seen or seen.add(x))]

        # Get unique files and limit number of file
        recent_spatialite = unique(recent_spatialite)
        recent_spatialite = recent_spatialite[:NB_RECENT_SPATIALITE]
        settings.setValue(BASE_SETTINGS_KEY + RECENT_SPATIALITE_KEY, recent_spatialite)

        # Update actions
        define_recent_spatialite_action(recent_spatialite)

        # update database if not up-to-date with xplordb schema
        if openlog.openlog_connection.updater.need_update():
            openlog.openlog_connection.updater.update_database(openlog.iface)
            openlog._unload_loaded_layer()

    def spatialite_connect():
        filename, filter_use = QFileDialog.getOpenFileName(
            openlog.iface.mainWindow(),
            "Select file",
            "",
            "Spatialite database (*.db)",
        )
        if filename:
            _open_spatialite_file(filename)

    def add_recent_spatialite_action(file: str):
        """
        Add an action for spatialite file open

        Args:
            file: (str) filename
        """

        action = QAction(
            QgsApplication.getThemeIcon("mIconSpatialite.svg"),
            file,
            openlog.iface.mainWindow(),
        )
        action.triggered.connect(lambda clicked: _open_spatialite_file(file))
        spatialite_menu.addAction(action)

    def define_recent_spatialite_action(file_list: list[str]):

        """
        Define action for recent spatialite file open

        Args:
            file_list: [str] recent files
        """

        # Remove recent file actions
        actions = spatialite_menu.actions()
        for del_action in actions[1:]:
            spatialite_menu.removeAction(del_action)
        # Add action for files
        for file in file_list:
            add_recent_spatialite_action(file)

    # Qaction and QMenu creation
    spatialite_connect_action = QAction(
        QgsApplication.getThemeIcon("mIconSpatialite.svg"),
        PLUGIN_NAME,
        openlog.iface.mainWindow(),
    )

    spatialite_menu = QMenu(openlog.iface.mainWindow())
    spatialite_connect_action.setMenu(spatialite_menu)

    # create action
    open_action = QAction(
        QIcon(str(DIR_PLUGIN_ROOT / "resources" / "images" / "import_collar.svg")),
        "Open...",
        openlog.iface.mainWindow(),
    )
    # connect to slot
    open_action.triggered.connect(spatialite_connect)

    # add to menu
    spatialite_menu.addAction(open_action)

    # recent spatialite files
    settings = QgsSettings()
    recent_spatialite = _get_recent_spatialite_files()
    if isinstance(recent_spatialite, str):
        recent_spatialite = [recent_spatialite]
    if recent_spatialite is not None:
        define_recent_spatialite_action(recent_spatialite)

    return spatialite_connect_action


@hookimpl
def connection():
    return ConnectionHook(
        name=PLUGIN_NAME,
        connection_action=spatialite_menu,
        connection_class=SpatialiteConnection,
    )
