import * as log from "loglevel";
import {
  LOCAL_STORAGE_QUOTA_EXCEEDED_MESSAGE,
  LOCAL_STORAGE_NO_SPACE_LEFT_ON_DEVICE_MESSAGE,
  LOCAL_STORAGE_NOT_SUPPORTED_APP_MIGHT_NOT_WORK_AS_EXPECTED,
  createMessage,
} from "ee/constants/messages";
import { toast } from "design-system";

export const LOCAL_STORAGE_KEYS = {
  CANVAS_CARDS_STATE: "CANVAS_CARDS_STATE",
  SPLITPANE_ANNOUNCEMENT: "SPLITPANE_ANNOUNCEMENT",
};

class LocalStorageNotSupportedError extends Error {
  name: string;
  constructor() {
    super();
    this.name = "LOCAL_STORAGE_NOT_SUPPORTED";
  }
}

class WebStorage {
  private storage: Storage;
  private _isSupported: boolean;

  constructor(storage: Storage) {
    this.storage = storage;

    this._isSupported = this.isSupported();
  }
  // ref: https://github.com/Modernizr/Modernizr/blob/94592f279a410436530c7c06acc42a6e90c20150/feature-detects/storage/localstorage.js
  isSupported = () => {
    try {
      this.storage.setItem("test", "testA");
      this.storage.removeItem("test");
      return true;
    } catch (e) {
      return false;
    }
  };

  getItem = (key: string): string | null => {
    try {
      if (!this._isSupported) {
        throw new LocalStorageNotSupportedError();
      }
      return this.storage.getItem(key);
    } catch (error) {
      this.handleError(error as Error);
    }
    return null;
  };

  handleError = (e: Error) => {
    let message;
    if (e.name === "QuotaExceededError") {
      message = LOCAL_STORAGE_QUOTA_EXCEEDED_MESSAGE;
    } else if (e.name === "NS_ERROR_FILE_NO_DEVICE_SPACE") {
      message = LOCAL_STORAGE_NO_SPACE_LEFT_ON_DEVICE_MESSAGE;
    } else if (e.name === "LOCAL_STORAGE_NOT_SUPPORTED") {
      // Fail silently
      log.error(
        createMessage(
          LOCAL_STORAGE_NOT_SUPPORTED_APP_MIGHT_NOT_WORK_AS_EXPECTED,
        ),
      );
      return;
    }

    if (message) {
      toast.show(createMessage(message), {
        kind: "error",
      });
    } else {
      throw e;
    }
  };

  setItem = (key: string, value: string) => {
    try {
      if (!this._isSupported) {
        throw new LocalStorageNotSupportedError();
      }
      this.storage.setItem(key, value);
    } catch (error) {
      this.handleError(error as Error);
    }
  };

  removeItem = (key: string) => {
    try {
      if (!this._isSupported) {
        throw new LocalStorageNotSupportedError();
      }
      this.storage.removeItem(key);
    } catch (error) {
      this.handleError(error as Error);
    }
  };

  clear = () => {
    try {
      if (!this._isSupported) {
        throw new LocalStorageNotSupportedError();
      }
      this.storage.clear();
    } catch (error) {
      this.handleError(error as Error);
    }
  };
}

export class LocalStorage extends WebStorage {
  constructor() {
    super(window.localStorage);
  }
}

class SessionStorage extends WebStorage {
  constructor() {
    super(window.sessionStorage);
  }
}

const localStorage = new LocalStorage();
export const sessionStorage = new SessionStorage();

export default localStorage;
