import { Injectable } from '@angular/core';

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

export enum StorageTypes {
    Local,
    Session,
}

export 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:
                WindowFunction().sessionStorage.setItem(key, JSON.stringify(value));
                break;
            case StorageTypes.Local:
            default:
                WindowFunction().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 | null {
        let item = null;
        switch (this._type) {
            case StorageTypes.Session:
                item = WindowFunction().sessionStorage.getItem(key);
                break;
            case StorageTypes.Local:
            default:
                item = WindowFunction().localStorage.getItem(key);
                break;
        }
        if (item) {
            try {
                return JSON.parse(<string>item);
            } catch (err) {
                // Ignore
            }
        }
        return null;
    }

    /**
     * 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 WindowFunction().sessionStorage.removeItem(key);
            case StorageTypes.Local:
            default:
                return WindowFunction().localStorage.removeItem(key);
        }
    }
}

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

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

    /**
     * Returns the native window the app is running in
     * @return window
     */
    public get nativeWindow(): globalThis.Window {
        return WindowFunction();
    }

    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 storage(type: StorageTypes = StorageTypes.Local): Storage | null {
        switch (type) {
            case StorageTypes.Local:
                return this._localStorage;
            case StorageTypes.Session:
                return this._sessionStorage;
            default:
                return null;
        }
    }
}
