import os
import pathlib
import json
from json.decoder import JSONDecodeError

import sanpy
import sanpy.interface
import sanpy.interface.sanpy_app as sanpy_app

from sanpy.sanpyLogger import get_logger

logger = get_logger(__name__)


class preferences:
    """Class to hold GUI preferences.

    Created and used by sanpy app SanPyWindow.
    """

    def __init__(self, sanpyApp: sanpy_app):
        super().__init__()
        self._sanpyApp = sanpyApp

        # bump this when we change, sanpy app will rebuild if loaded preerences are out of date
        # self._version = 1.2  # increment when we change preferences
        self._version = 1.3  # added set spike
        self._version = 1.4  # converted plugins from list[str] to dict to include externalWindow option
        self._version = 1.5  # adding keys to plugins (l, t, w, h)

        self._maxRecent = 7  # a lucky number
        self._configDict = self.load()

    def __setitem__(self, key, item):
        self._configDict[key] = item

    def __getitem__(self, key):
        return self._configDict[key]

    @property
    def configDict(self):
        return self._configDict

    def addFolder(self, path: str):
        """Add a folder to preferences."""
        logger.info(f"{path}")

        # add if not in recentFolders
        if not path in self.configDict["recentFolders"]:
            self.configDict["recentFolders"].append(path)
            # limit list to last _maxNumUndo
            self.configDict["recentFolders"] = self.configDict["recentFolders"][
                -self._maxRecent :
            ]

        # always set as the most recent folder
        self.configDict["mostRecentFolder"] = path

    def addPlugin(self, pluginName: str, externalWindow: bool, ltwhTuple: tuple):
        """Add plugin to preferences."""
        # was this as list
        # if not pluginName in self.configDict['pluginPanels']:
        #     self.configDict['pluginPanels'].append(pluginName)
        if not pluginName in self.configDict["pluginPanels"].keys():
            self.configDict["pluginPanels"][pluginName] = {
                "externalWindow": externalWindow,
                "l": ltwhTuple[0],
                "t": ltwhTuple[1],
                "w": ltwhTuple[2],
                "h": ltwhTuple[3],
            }

    def removePlugin(self, pluginName: str):
        """Remove plugin from preferences."""
        # was this as list
        # if pluginName in self.configDict['pluginPanels']:
        #     self.configDict['pluginPanels'].remove(pluginName)
        if pluginName in self.configDict["pluginPanels"].keys():
            self.configDict["pluginPanels"].pop(pluginName)

    def getMostRecentFolder(self):
        return self.configDict["mostRecentFolder"]

    def getRecentFolder(self):
        return self.configDict["recentFolders"]

    def preferencesSet(self, key1, key2, val):
        """Set a preference. See `getDefaults()` for key values."""
        try:
            self._configDict[key1][key2] = val

            # actually show hide some widgets
            # if key1=='display' and key2=='showScatter':
            #    if val:
            #        self.myScatterPlotWidget.show()
            #    else:
            #        self.myScatterPlotWidget.hide()

            # if key1=='display' and key2=='showErrors':
            #    if val:
            #        self.myErrorTable.show()
            #    else:
            #        self.myErrorTable.hide()

        except KeyError as e:
            logger.error(f'Did not set preference with keys "{key1}" and "{key2}"')

    def preferencesGet(self, key1, key2):
        """Get a preference. See `getDefaults()` for key values."""
        try:
            return self._configDict[key1][key2]
        except KeyError as e:
            logger.error(f'Did not get preference with keys "{key1}" and "{key2}"')

    def getPreferencesFile(self):
        userPreferencesFolder = sanpy._util._getUserPreferencesFolder()
        optionsFile = pathlib.Path(userPreferencesFolder) / "sanpy_preferences.json"
        return optionsFile

    def load(self):
        """
        Always load preferences from:
            <user>/Documents/SanPy/preferences/sanpy_preferences.json
        """

        preferencesFile = self.getPreferencesFile()

        useDefault = True
        if os.path.isfile(preferencesFile):
            logger.info(f"Loading preferences file")
            logger.info(f"  {preferencesFile}")
            try:
                with open(preferencesFile) as f:
                    loadedJson = json.load(f)
                    loadedVersion = loadedJson["version"]
                    logger.info(f"  loaded preferences version {loadedVersion}")
                    if loadedVersion < self._version:
                        # use default
                        logger.warning(
                            "  older version found, reverting to current defaults"
                        )
                        logger.warning(
                            f"  loadedVersion:{loadedVersion} currentVersion:{self._version}"
                        )
                        pass
                    else:
                        return loadedJson
            except JSONDecodeError as e:
                logger.error(e)
            except TypeError as e:
                logger.error(e)
        if useDefault:
            logger.info(f"Using default options")
            return self.getDefaults()

    def getDefaults(self) -> dict:
        """Get default preferences.

        Be sure to increment self._version when making changes.
        """
        configDict = {}  # OrderedDict()

        configDict["version"] = self._version
        configDict["useDarkStyle"] = True
        configDict[
            "autoDetect"
        ] = True  # FALSE DOES NOT WORK!!!! auto detect on file selection and/or sweep selection

        configDict["recentFolders"] = []
        configDict["mostRecentFolder"] = ""

        configDict["windowGeometry"] = {}
        configDict["windowGeometry"]["x"] = 100
        configDict["windowGeometry"]["y"] = 100
        configDict["windowGeometry"]["width"] = 1000
        configDict["windowGeometry"]["height"] = 1000

        configDict["filePanels"] = {}
        configDict["filePanels"]["File Panel"] = True

        # panels withing detectionWidget -> myDetectionToolbar
        configDict["detectionPanels"] = {}
        configDict["detectionPanels"]["Detection Panel"] = True  # main panel
        configDict["detectionPanels"]["Detection"] = True
        configDict["detectionPanels"]["Display"] = True
        configDict["detectionPanels"]["Plot Options"] = False
        configDict["detectionPanels"]["Set Spikes"] = False

        # plugins to show at startup
        # 20230325 convert from List[str] to dict
        configDict["pluginPanels"] = {}

        # values in detectionWidget -> myDetectionToolbar
        configDict["detect"] = {}
        configDict["detect"]["detectDvDt"] = 20
        configDict["detect"]["detectMv"] = -20

        # display options within detectionWidget -> myDetectionToolbar
        configDict["rawDataPanels"] = {}
        configDict["rawDataPanels"]["plotEveryPoint"] = 10  # not used?
        configDict["rawDataPanels"]["Full Recording"] = True  #
        configDict["rawDataPanels"]["Derivative"] = False  #
        configDict["rawDataPanels"]["DAC"] = False  #

        return configDict

    def save(self):
        preferencesFile = self.getPreferencesFile()

        logger.info(f'Saving preferences file as: "{preferencesFile}"')

        # get the current position and size of the main window
        left, top, width, height = self._sanpyApp.getWindowGeometry()

        self._configDict["windowGeometry"]["x"] = left
        self._configDict["windowGeometry"]["y"] = top
        self._configDict["windowGeometry"]["width"] = width
        self._configDict["windowGeometry"]["height"] = height

        # TODO: extend to a list
        # self._configDict['lastPath'] = self._sanpyApp.path

        # TODO: get window position and size of all open plugins
        # self.configDict['pluginPanels'][pluginName] = {'externalWindow': externalWindow,
        #                                                    'l': ltwhTuple[0],
        #                                                    't': ltwhTuple[1],
        #                                                    'w': ltwhTuple[2],
        #                                                    'h': ltwhTuple[3],
        #                                                    }
        _openSet = self._sanpyApp.myPlugins._openSet
        for _onePlugin in _openSet:
            pluginName = _onePlugin.myHumanName
            ltwhTuple = _onePlugin.getWindowGeometry()
            self.configDict["pluginPanels"][pluginName]["l"] = ltwhTuple[0]
            self.configDict["pluginPanels"][pluginName]["t"] = ltwhTuple[1]
            self.configDict["pluginPanels"][pluginName]["w"] = ltwhTuple[2]
            self.configDict["pluginPanels"][pluginName]["h"] = ltwhTuple[3]

        #
        # save
        with open(preferencesFile, "w") as outfile:
            json.dump(self._configDict, outfile, indent=4, sort_keys=True)

        self._sanpyApp.slot_updateStatus("Saved preferences")
