import { getAppFromInstance } from '../global';
import { MustardName } from '../typings';

export function proxyStorage (appName:MustardName, _storage:typeof localStorage|typeof sessionStorage) {

    const nullObject = JSON.stringify(Object.create(null));

    const getItem = _storage.getItem.bind(_storage);
    const setItem = _storage.setItem.bind(_storage);
    const removeItem = _storage.removeItem.bind(_storage);

    const app = getAppFromInstance(appName);
    const origin = new URL(app.url)?.origin;

    function _getAllItem () {
        return JSON.parse(getItem(origin) ?? nullObject) as Record<string, string>;
    }
    function _getItem (key:string) {
        return _getAllItem()[key];
    }
    function _setItem (value:Record<string, string>) {
        return setItem(origin, JSON.stringify(value));
    }

    class Storage {
        constructor () {
            const data = _getAllItem();
            Reflect.ownKeys(data).forEach((key:string) => {
                this[key] = data[key];
            });
        }
        get length () {
            const data = _getAllItem();
            return Reflect.ownKeys(data)?.length;
        }
        clear () {
            Reflect.ownKeys(this).forEach(key => {
                Reflect.deleteProperty(this, key);
            });
            removeItem(origin);
        }
        getItem (key:string) {
            return _getItem(key);
        }
        setItem (key:string, value:unknown) {
            const data = _getAllItem();
            this[key] = data[key] = value?.toString?.();
            return _setItem(data);
        }
        removeItem (key:string) {
            const data = _getAllItem();
            Reflect.deleteProperty(this, key);
            const result = Reflect.deleteProperty(data, key);
            _setItem(data);
            return result;
        }
        key (index:number) {
            const data = _getAllItem();
            return Reflect.ownKeys(data)[index];
        }
    }

    const storage = new Storage();

    return new Proxy(storage, {
        get (target, key:string) {
            if(key === 'length') {
                return target.length;
            }else if(['clear', 'getItem', 'setItem', 'removeItem', 'key'].includes(key)) {
                return target[key].bind(target);
            }else{
                return _getItem(key);
            }
        },
        set (target, key:string, value:unknown) {
            if(key === 'length') return value;
            return target.setItem(key, value);
        },
        ownKeys () {
            const data = _getAllItem();
            return Reflect.ownKeys(data);
        },
        deleteProperty (target, key:string) {
            return target.removeItem(key);
        }
    });
}

export function proxyLocalStorage (appName:MustardName) {
    return proxyStorage(appName, localStorage);
}

export function proxySessionStorage (appName:MustardName) {
    return proxyStorage(appName, sessionStorage);
}