import PropTypes from 'prop-types';

export default class LocalStorageHandler {

    //TODO add proper validation
    static VALID_KEYS = {
        //used to store a SearchResults object obtained after calling the SearchAPI
        'stored-search-results': "object", //SearchResults.toLocalStorageObject()

        //used to store the priority query, so it can be run by passing the query=prio param (single search)
        'stored-priority-query': "object", //Query

        //used to remember selected search results across the media suite
        'stored-selections' : "array", //containing objects with: key=resourceId value=SearchResult

        //used to remember the active project across the media suite
        'stored-active-project': "object", //Project

        //used when clicking on an item in the result list
        'stored-visited-results': "array", //containing strings

        //whether the user wants to show/hide the time line on the search page
        'state-show-timeline': "boolean",

        //store active (if any has been selected) collection id.
        'active-collection-id': "string",

        //collections ids selected in Collection inspector.
        'stored-cids': "string",

        //queries selected for further query processing (see ProjectQueriesView)
        'stored-query-selection' : "object"
    };

    static supportsHTML5Storage = () => {
		try {
			return 'localStorage' in window && window['localStorage'] !== null
		} catch (e) {
			return false
		}
    };

    static checkLocalStorageKey = (key, mustExist) => {
        if(key in LocalStorageHandler.VALID_KEYS){
            if(!mustExist || (mustExist && localStorage.getItem(key))){
                return true;
            }
        }
        return false;
    };

    //TODO turn this into something that tries to construct & validate the actual object/class based on the stored JSON data
    static checkProptype = (key, data) => {
        let propType = '';
        if(Array.isArray(data)){
            propType = "array";
        } else {
            propType = typeof data;
        }
        if(propType === LocalStorageHandler.VALID_KEYS[key]){
            return true;
        }
        return false;
    };

    /*--------------------------------------------------------------------------------
	* ------------------------- CRUD OF JSON OBJECTS IN LOCALSTORAGE -----------------
	---------------------------------------------------------------------------------*/

    static deleteUnusedKeys = () => {
        for (let i = 0; i < localStorage.length; i++) {
            if(LocalStorageHandler.VALID_KEYS[localStorage.key(i)] === undefined) {
                try { localStorage.removeItem(localStorage.key(i)); } catch (e) { }
            }
        }
    };

    //Note: localStorage stored class objects like a simple JSON structure without functions.
    //When retrieving the object, don't expect the functions to be there, instead use Object.construct to recreate the original object
    static storeJSONInLocalStorage = (key, data) => {
        LocalStorageHandler.deleteUnusedKeys(); //always make sure to delete unused keys...
        if(LocalStorageHandler.supportsHTML5Storage() && LocalStorageHandler.checkLocalStorageKey(key, false)) {
            if(LocalStorageHandler.checkProptype(key, data)){
                try {
                    if(data === null) {
                        localStorage.removeItem(key);
                    } else {
                        localStorage.setItem(key, JSON.stringify(data));
                    }
                    return true
                } catch (e) {
                    console.error(e);
                }
            } else {
                console.error('Trying to store the wrong kind of data for key: ' + key)
            }
        }
        return false
    };

    //TODO possibly extend with an option to cast the JSON back to the original object (see the model package)
	static getJSONFromLocalStorage = key => {
		if(LocalStorageHandler.supportsHTML5Storage() && LocalStorageHandler.checkLocalStorageKey(key, true)) {
			try {
				return JSON.parse(localStorage.getItem(key))
			} catch (e) {
				console.error(e);
			}
		}
		return null
	};

	static removeJSONByKeyInLocalStorage = key => {
        if (LocalStorageHandler.supportsHTML5Storage() && LocalStorageHandler.checkLocalStorageKey(key, true)) {
            try {
                localStorage.removeItem(key);
                return true
            } catch (e) {
                console.error(e);
            }
        }
        return false
    };

	/*--------------------------------------------------------------------------------
	* ------------------------- CRUD OF ARRAYS WITH OJECTS/IDS IN LOCALSTORAGE -------
	---------------------------------------------------------------------------------*/

	//if you are pushing an object to the stored array, make sure to supply the identifier field name (string) of that object
	static pushItemToLocalStorage = (key, item, itemIdentifier=null) => {
        if(LocalStorageHandler.checkLocalStorageKey(key, false)){
            const currentDataOnStorage = LocalStorageHandler.getJSONFromLocalStorage(key);
            let obj = null;
            if(currentDataOnStorage === null) {
                obj = [item];
                this.storeJSONInLocalStorage(key, obj)
            } else {
                // if item is not in array then push it.
                if(!currentDataOnStorage.find(val => {
                    if(itemIdentifier) { //for comparing objects
                        return val[itemIdentifier] === item[itemIdentifier];
                    } else {
                        return val === item;
                    }
                })) {
                    currentDataOnStorage.push(item);
                }
                this.storeJSONInLocalStorage(key, currentDataOnStorage)
            }
        }
        return null;
    };

	//if you are removing an object from the stored array, make sure to supply the identifier field name (string) of that object
    static removeItemInLocalStorage = (key, item, itemIdentifier=null) => {
        if(LocalStorageHandler.checkLocalStorageKey(key, false)){
            const currentDataOnStorage = LocalStorageHandler.getJSONFromLocalStorage(key);
            const index = currentDataOnStorage.findIndex(val => {
                if(itemIdentifier) { //for comparing objects
                    return val[itemIdentifier] === item[itemIdentifier]
                } else {
                    return val === item
                }
            });
            currentDataOnStorage.splice(index, 1);
            if(currentDataOnStorage.length > 0) {
                this.storeJSONInLocalStorage(key, currentDataOnStorage);
            } else {
               this.removeJSONByKeyInLocalStorage(key);
            }
        }
    };

    /*--------------------------------------------------------------------------------
    * ------------------------- HIGH-LEVEL CONVENIENCE FUNCTIONS ---------------------
    ---------------------------------------------------------------------------------*/

    static storeQueries = (project, queryIds) => {
        if(!project || !queryIds) return;
        LocalStorageHandler.storeJSONInLocalStorage(
            'stored-query-selection',
            {
                projectId : project.id,
                queryIds : queryIds
            }
        );
    };

    static getStoredQueries = () => {
        return LocalStorageHandler.getJSONFromLocalStorage('stored-query-selection');
    };

    static updateStoredQueries = (project, queriesToDelete) => {
        if(!project || !queriesToDelete) return;

        const storedQueryData = LocalStorageHandler.getStoredQueries();
        if(storedQueryData && storedQueryData.projectId !== project.id) return;

        queriesToDelete.forEach(nq => {
            if(storedQueryData.queryIds.includes(nq.query.id)) {
                storedQueryData.queryIds.splice(
                    storedQueryData.queryIds.indexOf(nq.query.id),
                    1
                );
            }
        })
        LocalStorageHandler.storeQueries(project, storedQueryData.queryIds);
    };

};