import { Injectable } from '@pecometer/pecular/core';

function LocalWindow(): globalThis.Window {
    return window;
}

export enum StorageTypes {
    Local,
    Session,
}

class Storage {
    private _type: StorageTypes;

    constructor(type: StorageTypes = StorageTypes.Local) {
        this._type = type;
    }

    /**
     * Sets a value in the storage container
     * @param string - the key/name of the value to be stored
     * @param any - the value to be stored
     * @return void
     */
    public set(key: string, value: unknown): void {
        switch (this._type) {
            case StorageTypes.Session:
                LocalWindow().sessionStorage.setItem(key, JSON.stringify(value));
                break;
            case StorageTypes.Local:
            default:
                LocalWindow().localStorage.setItem(key, JSON.stringify(value));
                break;
        }
    }

    /**
     * Gets a value in the storage container
     * @param string - the key/name of the value to be returned
     * @return any/null
     */
    public get(key: string): unknown {
        switch (this._type) {
            case StorageTypes.Session:
                return JSON.parse(LocalWindow().sessionStorage.getItem(key));
            case StorageTypes.Local:
            default:
                return JSON.parse(LocalWindow().localStorage.getItem(key));
        }
    }

    /**
     * Removes a value in the storage container
     * @param string - the key/name of the value to be removed
     * @return void
     */
    public remove(key: string): void {
        switch (this._type) {
            case StorageTypes.Session:
                return LocalWindow().sessionStorage.removeItem(key);
            case StorageTypes.Local:
            default:
                return LocalWindow().localStorage.removeItem(key);
        }
    }
}

@Injectable()
export class StorageService {
    private _localStorage: Storage;
    private _sessionStorage: Storage;

    constructor() {
        this._localStorage = new Storage(StorageTypes.Local);
        this._sessionStorage = new Storage(StorageTypes.Session);
    }

    public get localStorage(): Storage {
        return this._localStorage;
    }

    public get sessionStorage(): Storage {
        return this._sessionStorage;
    }

    /**
     * Returns the storage container as requested by type parameter
     * @param StorageTypes - the type of storage to return
     * @return Storage
     */
    public get(type: StorageTypes = StorageTypes.Local): Storage | null {
        switch (type) {
            case StorageTypes.Local:
                return this._localStorage;
            case StorageTypes.Session:
                return this._sessionStorage;
            default:
                return null;
        }
    }
}
