# coding=utf-8
"""
Implementation for:
- GUISettings: class containing all the settings for the GUI
"""
import os

from termcolor import colored

import UEVaultManager.tkgui.modules.functions_no_deps as gui_fn
from UEVaultManager.lfs.utils import clean_filename
from UEVaultManager.models.config import AppConf

# NOTE : we can't import the following modules here because of circular dependencies
# UEVaultManager.tkgui.modules.functions_no_deps


def log(msg: str) -> None:
    """
    Print a message to the console
    :param msg: the message to log
    """
    msg = colored(msg, 'orange')
    print(msg)


class GUISettings:
    """
    This class contains all the settings for the GUI.
    :param config_file: Path to config file to use instead of default

    """

    def __init__(self, config_file=None):
        self.path = ''
        self.config_path = ''
        self.config = AppConf(comment_prefixes='/', allow_no_value=True)

        self.init_gui_config_file(config_file)

        # ##### start of properties stored in config file
        # store all the properties that must be saved in config file
        self.config_vars = {
            'debug_mode': gui_fn.convert_to_bool(self.config.get('UEVaultManager', 'debug_mode', fallback=False)),
            'never_update_data_files': gui_fn.convert_to_bool(self.config.get('UEVaultManager', 'never_update_data_files', fallback=False)),
            'reopen_last_file': gui_fn.convert_to_bool(self.config.get('UEVaultManager', 'reopen_last_file', fallback=False)),
            'use_colors_for_data': gui_fn.convert_to_bool(self.config.get('UEVaultManager', 'use_colors_for_data', fallback=True)),
            'image_cache_max_time': int(self.config.get('UEVaultManager', 'image_cache_max_time', fallback=60 * 60 * 24 * 15)),
            'last_opened_file': self.config.get('UEVaultManager', 'last_opened_file', fallback=''),
            'cache_folder': self.config.get('UEVaultManager', 'cache_folder', fallback='../../../cache'),
            'results_folder': self.config.get('UEVaultManager', 'results_folder', fallback='../../../results')
        }

        # the following folders are relative to the current file location
        # they must be used trought path_from_relative_to_absolute
        # following vars are not set as properties to avoid storing absolute paths in the config file
        self.cache_folder = gui_fn.path_from_relative_to_absolute(self.config_vars['cache_folder'])
        self.results_folder = gui_fn.path_from_relative_to_absolute(self.config_vars['results_folder'])

        # Folder for assets (aka. images, icon... not "UE assets") used for the GUI. THIS IS NOT A SETTING THAT CAN BE CHANGED BY THE USER
        self.assets_folder = gui_fn.path_from_relative_to_absolute('../../assets')

        self.app_icon_filename = os.path.join(self.assets_folder, 'main.ico')
        self.default_image_filename = os.path.join(self.assets_folder, 'UEVM_200x200.png')

        if self.config_vars['reopen_last_file'] and os.path.isfile((self.config_vars['last_opened_file'])):
            self.csv_filename = self.config_vars['last_opened_file']
        else:
            self.csv_filename = os.path.join(self.config_vars['results_folder'], 'list.csv')

        self.csv_filename = os.path.normpath(self.csv_filename)
        self.app_title = 'UEVM Gui'
        self.app_width = 1600
        self.app_height = 935
        self.app_monitor = 1
        self.csv_datetime_format = '%Y-%m-%d %H:%M:%S'
        self.data_filetypes = (('csv file', '*.csv'), ('tcsv file', '*.tcsv'), ('json file', '*.json'), ('text file', '*.txt'))
        self.preview_max_width = 150
        self.preview_max_height = 150
        self.default_global_search = 'Text to search...'
        self.default_category_for_all = 'All'
        self.empty_cell = 'nan'
        self.expand_columns_factor = 20
        self.contract_columns_factor = 20
        # ttkbootstrap themes:
        # light themes : "cosmo", "flatly", "litera", "minty", "lumen", "sandstone", "yeti", "pulse", "united", "morph", "journal", "simplex", "cerculean"
        # dark themes: "darkly", "superhero", "solar", "cyborg", "vapor"
        self.theme_name = 'lumen'
        self.theme_font = ('Verdana', 8)
        self.datatable_default_pref = {
            'align': 'w',  #
            'cellbackgr': '#F4F4F3',  #
            'cellwidth': 100,  #
            'floatprecision': 2,  #
            'thousandseparator': '',  #
            'font': 'Verdana',  #
            'fontsize': 8,  #
            'fontstyle': '',  #
            'grid_color': '#ABB1AD',  #
            'linewidth': 1,  #
            'rowheight': 22,  #
            'rowselectedcolor': '#E4DED4',  #
            'textcolor': 'black'  #
        }

    def get_debug_mode(self):
        """ Getter for debug_mode """
        return self.config_vars['debug_mode']

    def set_debug_mode(self, value):
        """ Setter for debug_mode """
        self.config_vars['debug_mode'] = value

    def get_never_update_data_files(self):
        """ Getter for never_update_data_files """
        return self.config_vars['never_update_data_files']

    def set_never_update_data_files(self, value):
        """ Setter for never_update_data_files """
        self.config_vars['never_update_data_files'] = value

    def get_reopen_last_file(self):
        """ Getter for reopen_last_file """
        return self.config_vars['reopen_last_file']

    def set_reopen_last_file(self, value):
        """ Setter for reopen_last_file """
        self.config_vars['reopen_last_file'] = value

    def get_use_colors_for_data(self):
        """ Getter for use_colors_for_data """
        return self.config_vars['use_colors_for_data']

    def set_use_colors_for_data(self, value):
        """ Setter for use_colors_for_data """
        self.config_vars['use_colors_for_data'] = value

    def get_image_cache_max_time(self):
        """ Getter for image_cache_max_time """
        return self.config_vars['image_cache_max_time']

    def set_image_cache_max_time(self, value):
        """ Setter for image_cache_max_time """
        self.config_vars['image_cache_max_time'] = value

    def get_last_opened_file(self):
        """ Getter for last_opened_file """
        return self.config_vars['last_opened_file']

    def set_last_opened_file(self, value):
        """ Setter for last_opened_file """
        self.config_vars['last_opened_file'] = value

    def get_cache_folder(self):
        """ Getter for cache_folder """
        return self.config_vars['cache_folder']

    def set_cache_folder(self, value):
        """ Setter for cache_folder """
        self.config_vars['cache_folder'] = value

    def get_results_folder(self):
        """ Getter for results_folder """
        return self.config_vars['results_folder']

    def set_results_folder(self, value):
        """ Setter for results_folder """
        self.config_vars['results_folder'] = value

    # use properties for keeping transparent access to these properties
    debug_mode = property(get_debug_mode, set_debug_mode)
    never_update_data_files = property(get_never_update_data_files, set_never_update_data_files)
    reopen_last_file = property(get_reopen_last_file, set_reopen_last_file)
    use_colors_for_data = property(get_use_colors_for_data, set_use_colors_for_data)
    image_cache_max_time = property(get_image_cache_max_time, set_image_cache_max_time)
    last_opened_file = property(get_last_opened_file, set_last_opened_file)

    # following vars are not set as properties to avoid storing absolute paths in the config file
    # getter and setter could be used to store relative paths
    # cache_folder = property(get_cache_folder, set_cache_folder)
    # results_folder = property(get_results_folder, set_results_folder)

    def init_gui_config_file(self, config_file: str = '') -> None:
        """
        Initialize the config file for the gui
        :param config_file: the path to the config file to use
        """
        if config_path := os.environ.get('XDG_CONFIG_HOME'):
            self.path = os.path.join(config_path, 'UEVaultManager')
        else:
            self.path = os.path.expanduser('~/.config/UEVaultManager')
        if not os.path.isdir(self.path):
            os.makedirs(self.path)
        if config_file:
            if os.path.exists(config_file):
                self.config_path = os.path.abspath(config_file)
            else:
                self.config_path = os.path.join(self.path, clean_filename(config_file))
            log(f'UEVMGui is using non-default config file "{self.config_path}"')
        else:
            self.config_path = os.path.join(self.path, 'config_gui.ini')

        # try loading config
        try:
            self.config.read(self.config_path)
        except Exception as error:
            log('Unable to read configuration file, please ensure that file is valid! '
                f'(Error: {repr(error)})')
            log('Continuing with blank config in safe-mode...')
            self.config.read_only = True

        config_defaults = {
            'debug_mode': {
                'comment': 'Set to True to print debug information (GUI related only',
                'value': 'False'
            },
            'never_update_data_files': {
                'comment': 'Set to True to speed the update process by not updating the metadata files. FOR TESTING ONLY',
                'value': 'False'
            },
            'reopen_last_file': {
                'comment': 'Set to True to re-open the last file at startup if no input file is given',
                'value': 'True'
            },
            'use_colors_for_data': {
                'comment': 'Set to True to enable cell coloring depending on its content.It could slow down data and display refreshing',
                'value': 'True'
            },
            'last_opened_file': {
                'comment': 'File name of the last opened file',
                'value': ''
            },
            'image_cache_max_time': {
                'comment': 'Delay in seconds when image cache will be invalidated. Default value represent 15 days',
                'value': str(60 * 60 * 24 * 15)
            },
            'cache_folder': {
                'comment': 'Folder (relative or absolute) to store cached data for assets (mainly preview images)',
                'value': '../../../cache'
            },
            'results_folder': {
                'comment': 'Folder (relative or absolute) to store result files to read and save data from',
                'value': '../../../results'
            },
        }

        has_changed = False
        if 'UEVaultManager' not in self.config:
            self.config.add_section('UEVaultManager')
            has_changed = True

        for option, content in config_defaults.items():
            if not self.config.has_option('UEVaultManager', option):
                self.config.set('UEVaultManager', f';{content["comment"]}')
                self.config.set('UEVaultManager', option, content['value'])
                has_changed = True

        if has_changed:
            self.save_config_file(save_config_var=False)

    def store_config_properties(self) -> None:
        """
        store the properties in the config file
        """
        for key, value in self.config_vars.items():
            self.config.set('UEVaultManager', key, str(value))

    def save_config_file(self, save_config_var=True) -> None:
        """
        Save the config file
        """
        if save_config_var:
            self.store_config_properties()
            self.config.modified = True

        # do not save if in read-only mode or file hasn't changed
        if self.config.read_only or not self.config.modified:
            return

        # if config file has been modified externally, back-up the user-modified version before writing
        if os.path.exists(self.config_path):
            if (mod_time := int(os.stat(self.config_path).st_mtime)) != self.config.mod_time:
                new_filename = f'config.{mod_time}.ini'
                log(
                    f'Configuration file has been modified while UEVaultManager was running\nUser-modified config will be renamed to "{new_filename}"...'
                )
                os.rename(self.config_path, os.path.join(os.path.dirname(self.config_path), new_filename))

        with open(self.config_path, 'w') as cf:
            self.config.write(cf)
