import os, enum, pathlib, re
from qgis.core import *
from qgis.gui import *
from qgis.PyQt.QtCore import *
from qgis.PyQt.QtWidgets import *
from qgis.PyQt.QtGui import *

from eotimeseriesviewer import *
from eotimeseriesviewer.utils import loadUI


class Keys(enum.Enum):
    """
    Enumeration of settings keys.
    """
    DateTimePrecision = 'date_time_precision'
    MapSize = 'map_size'
    MapUpdateInterval = 'map_update_interval'
    MapBackgroundColor = 'map_background_color'
    ScreenShotDirectory = 'screen_shot_directory'
    RasterSourceDirectory = 'raster_source_directory'
    VectorSourceDirectory = 'vector_source_directory'

_VALID_KEYS = list(Keys)
_VALID_KEYSTRING = [k.value for k in _VALID_KEYS]
_VALID_KEYNAMES = [k.name for k in _VALID_KEYS]


def defaultValues() -> dict:
    """
    Returns the official hard-coded dictionary of default values.
    :return: dict
    """
    d = dict()
    from eotimeseriesviewer.timeseries import DateTimePrecision

    # general settings
    home = pathlib.Path.home()
    d[Keys.ScreenShotDirectory] = str(home)
    d[Keys.RasterSourceDirectory] = str(home)
    d[Keys.VectorSourceDirectory] = str(home)
    d[Keys.DateTimePrecision] = DateTimePrecision.Day

    # map visualization
    d[Keys.MapUpdateInterval] = 500  # milliseconds
    d[Keys.MapSize] = QSize(300, 300)
    d[Keys.MapBackgroundColor] = QColor('black')
    # tbd. other settings

    return d


_DEFAULTS = defaultValues()



def settings()->QSettings:
    """
    Returns the EOTSV settings.
    :return: QSettings
    """
    settings = QSettings(QSettings.UserScope, 'HU-Berlin', 'EO-TimeSeriesViewer')

    return settings

def keyString(obj)->str:
    """
    Converts a string or key into the appropriate key string accessor for the QSettings object.

    :param obj:
    :return:
    """
    keyString = None
    if isinstance(obj, str):
        if obj in _VALID_KEYSTRING:
            keyString = _VALID_KEYS[_VALID_KEYSTRING.index(obj)].value
        elif obj in _VALID_KEYNAMES:
            keyString = _VALID_KEYS[_VALID_KEYNAMES.index(obj)].value
        else:
            keyString = obj
    elif isinstance(obj, Keys):
        keyString = obj.value
    return keyString


def value(key:Keys, default=None):
    """
    Provides direct access to a settings value
    :param key: str | Keys
    :param default: default value, defaults to None
    :return: value | None
    """
    ks = keyString(key)
    value = None
    try:
        value = settings().value(ks, defaultValue=default)
    except TypeError as error:
        value = None
        settings().setValue(ks, None)
        print(error, file=sys.stderr)
    return value


def setValue(key, value):
    """
    Shortcut to save a value into the EOTSV settings
    :param key: str | Key
    :param value: any value
    """
    ks = keyString(key)
    settings().setValue(ks, value)


def setValues(values: dict):
    """
    Writes the EOTSV settings
    :param values: dict
    :return:
    """
    S = settings()
    assert isinstance(S, QSettings)
    assert isinstance(values, dict)

    for key, val in values.items():
        ks = keyString(key)
        if isinstance(ks, str):
            S.setValue(ks, values[key])
    pass


class SettingsDialog(QDialog, loadUI('settingsdialog.ui')):
    """
    A widget to change settings
    """

    def __init__(self, title='<#>', parent=None):
        super(SettingsDialog, self).__init__(parent)
        self.setupUi(self)

        assert isinstance(self.cbDateTimePrecission, QComboBox)
        from eotimeseriesviewer.timeseries import DateTimePrecision
        for e in DateTimePrecision:
            assert isinstance(e, enum.Enum)
            self.cbDateTimePrecission.addItem(e.name, e)

        self.mFileWidgetScreenshots.setStorageMode(QgsFileWidget.GetDirectory)
        self.mFileWidgetRasterSources.setStorageMode(QgsFileWidget.GetDirectory)
        self.mFileWidgetVectorSources.setStorageMode(QgsFileWidget.GetDirectory)

        self.cbDateTimePrecission.currentIndexChanged.connect(self.validate)
        self.sbMapSizeX.valueChanged.connect(self.validate)
        self.sbMapSizeY.valueChanged.connect(self.validate)
        self.sbMapRefreshIntervall.valueChanged.connect(self.validate)

        assert isinstance(self.buttonBox, QDialogButtonBox)
        self.buttonBox.button(QDialogButtonBox.RestoreDefaults).clicked.connect(lambda: self.setValues(defaultValues()))
        self.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self.onAccept)
        self.buttonBox.button(QDialogButtonBox.Cancel)

        self.mLastValues = dict()

        self.setValues(settings())

    def validate(self, *args):

        values = self.values()

    def onAccept(self):
        pass
        self.setResult(QDialog.Accepted)

        values = self.values()
        setValues(values)
        if values != self.mLastValues:

            pass

    def values(self)->dict:
        """
        Returns the settings as dictionary
        :return: dict
        """
        d = dict()

        d[Keys.ScreenShotDirectory] = self.mFileWidgetScreenshots.filePath()
        d[Keys.RasterSourceDirectory] = self.mFileWidgetRasterSources.filePath()
        d[Keys.VectorSourceDirectory] = self.mFileWidgetVectorSources.filePath()

        d[Keys.DateTimePrecision] = self.cbDateTimePrecission.currentData()
        d[Keys.MapSize] = QSize(self.sbMapSizeX.value(), self.sbMapSizeY.value())
        d[Keys.MapUpdateInterval] = self.sbMapRefreshIntervall.value()
        d[Keys.MapBackgroundColor] = self.mCanvasColorButton.color()

        return d

    def setValues(self, values: dict):
        """
        Sets the values as stored in a dictionary or QSettings object
        :param values: dict | QSettings
        """

        if isinstance(values, QSettings):
            d = dict()
            for k in values.allKeys():
                d[k] = values.value(k)
            values = d

        assert isinstance(values, dict)

        def checkKey(val, key:Keys):
            assert isinstance(key, Keys)
            return val in [key, key.value, key.name]

        for key, value in values.items():
            if checkKey(key, Keys.ScreenShotDirectory) and isinstance(value, str):
                self.mFileWidgetScreenshots.setFilePath(value)
            if checkKey(key, Keys.RasterSourceDirectory) and isinstance(value, str):
                self.mFileWidgetRasterSources.setFilePath(value)
            if checkKey(key, Keys.VectorSourceDirectory) and isinstance(value, str):
                self.mFileWidgetVectorSources.setFilePath(value)

            if checkKey(key, Keys.DateTimePrecision):
                i = self.cbDateTimePrecission.findData(value)
                if i > -1:
                    self.cbDateTimePrecission.setCurrentIndex(i)

            if checkKey(key, Keys.MapSize) and isinstance(value, QSize):
                self.sbMapSizeX.setValue(value.width())
                self.sbMapSizeY.setValue(value.height())

            if checkKey(key, Keys.MapUpdateInterval) and isinstance(value, (float, int)) and value > 0:
                self.sbMapRefreshIntervall.setValue(value)

            if checkKey(key, Keys.MapBackgroundColor) and isinstance(value, QColor):
                self.mCanvasColorButton.setColor(value)