/**
 * @since Last modified: 2024/06/10 17:46:30
 * @namespace storage
 * @description Manipulations of localStorage and sessionStorage.
 * @property {function} set - Store or modify cache data.
 * @property {function} get - Get the cache data.
 * @property {function} remove - Remove the cache data.
 * @property {function} clear - Clear cache data.
 * @see {@link https://codepen.io/axui/pen/abXwOXm|demo @ codepen}
 * @example
 * ax.storage.set('myData',{a:0,b:1});
 */





'use strict';
import deepClone from './deepClone';
import getDataType from './getDataType';
import isEmpty from './isEmpty';
import extend from './extend';
import getExpiration from './getExpiration';

interface Options {
    unit: 's' | 'm' | 'h' | 'd',
    type: 'local' | 'session',
    expires: number | string,
    override: boolean
}
const storage = {
    /**
 * @memberOf storage
 * @description Storage cache data.Due to "JSON.stringify", node type and function type can't store.
 * @param {string} key - The name of cache data.
 * @param {*} value - The value of cache data.
 * @param {object} [options] - The options of cache data.
 * @param {string} [options.unit=d] - The date unit that calculates the expiration time.The default value is 'd'(day).
 * @param {number|string} [options.expires=0] - The value of The date unit.The default value is 365.The default value is 0(Never expire).
 * @param {boolean} [options.override=true] - Whether the original value is overrided in the same case.The default value is true.
 * @returns {*} Return storage itself.
 * @see {@link https://codepen.io/axui/pen/abXwOXm|demo @ codepen}
 * @example
 * ax.storage.set('myData',{a:0,b:1});
 */
    
    
    
    
    set: function (key: string, value: any, opts?: Options): any {
        
        if (isEmpty(key) && typeof key !== 'string') {
            return false;
        }
        let options = Object.assign({ unit: 'd', expires: 0, override: true, type: 'local' }, opts),
            newValue = deepClone(value),
            valType = getDataType(value),
            stor = options.type === 'session' ? window.sessionStorage : window.localStorage,
            filterProps = (obj: any): any => {
                Object.keys(obj).forEach(k => {
                    let val = obj[k];
                    (getDataType(val) === 'Array' || getDataType(val) === 'Object') && filterProps(val);
                    
                    (getDataType(val).includes('HTML') || getDataType(val) === 'Function') && delete obj[k];
                });
                return obj;
            };
        
        if ((valType === 'Array' || valType === 'Object') && !isEmpty(newValue)) {
            
            filterProps(newValue);
        }
        let expires = options.expires !== 0 ? getExpiration(options.unit, options.expires) : 0,
            oldValue = this.get(key, options.type),
            valueExp = {
                
                data: (!options.override && this.get(key, options.type)) ? extend({target:oldValue,source: newValue}) : newValue,
                
                expires,
            };
        
        if (((typeof options.expires === 'number' && options.expires < 0) || newValue === null) && this.get(key, options.type)) {
            this.remove(key, options.type);
        } else {
            stor.setItem(key, JSON.stringify(valueExp));
        }
        return this;
    },
    /**
    * @memberOf storage
    * @description Get cache data.
    * @param {string} key - The name of cache data.
    * @param {'local' | 'session'} [type='local'] - LocalStorage or sessionStorage.
    * @returns {string|null} Return localStorage data.
    * @see {@link https://codepen.io/axui/pen/abXwOXm|demo @ codepen}
    * @example
    * ax.storage.get('myData');
    */
    
    
    
    get: function (key: string, type: 'local' | 'session' = 'local'): any {
        
        if (isEmpty(key) || typeof key !== 'string') {
            return false;
        }
        let now = new Date().getTime(),
            stor = type === 'session' ? window.sessionStorage : window.localStorage,
            valueStr: any = stor.getItem(key);
        if (valueStr) {
            let valueExp: any = (new Function('return ' + valueStr))();
            
            if (valueExp.expires === 0 || now <= valueExp.expires) {
                
                return valueExp.data;
            } else {
                
                stor.removeItem(key);
                return null;
            }
        } else {
            
            return null;
        }
    },
    /**
    * @memberOf storage
    * @description Remove cache data.
    * @param {string} key - The name of cache data.
    * @param {'local' | 'session'} [type='local'] - LocalStorage or sessionStorage.
    * @returns {string|null} Return storage itself.
    * @see {@link https://codepen.io/axui/pen/abXwOXm|demo @ codepen}
    * @example
    * ax.storage.remove('myData');
    */
    
    
    
    remove: function (key: string, type: 'local' | 'session' = 'local'): any {
        
        if (isEmpty(key) || typeof key !== 'string') {
            return false;
        }
        let stor = type === 'session' ? window.sessionStorage : window.localStorage;
        stor.removeItem(key);
        return this;
    },
    /**
    * @memberOf storage
    * @description Clear all cache data.
    * @param {'local' | 'session'} [type='local'] - LocalStorage or sessionStorage.
    * @returns {string|null} Return storage itself.
    * @see {@link https://codepen.io/axui/pen/abXwOXm|demo @ codepen}
    * @example
    * ax.storage.clear();
    */
    
    
    clear: function (type: 'local' | 'session' = 'local'): any {
        let stor = type === 'session' ? window.sessionStorage : window.localStorage;
        stor.clear();
        return this;
    }
}
export default storage;
