import * as storageApi from '@/browser/storage';
import { useStorage } from '@vueuse/core';
import parseJs from 'parse-js';
import { loggerPlugin } from '@/plugins/logger';

const {
  storageSet,
  storageGet,
  storageRemove,
  storageClear,
} = storageApi;

const parseValueGet = (value, type, defaultVal) => {
  try {
    if (!value) {
      return defaultVal;
    }

    switch (type) {
      case 'json':
        return parseJs().json().parse(value);
      case 'number':
        return parseJs().number().parse(value);
      case 'bool':
        return parseJs().bool().parse(value);
      default:
        return value;
    }
  } catch (error) {
    loggerPlugin.error({
      msg: 'STORE_PARSE_ERROR',
      type,
      value,
      error,
    });
    return value || defaultVal;
  }
};

const parseValueSet = (value, type) => {
  switch (type) {
    case 'json':
      return JSON.stringify(value);
    case 'number':
    case 'bool':
      return value.toString();
    default:
      return value;
  }
};

const checkLocalStorageAvailable = () => {
  return typeof localStorage !== 'undefined';
};

const handleStorageGetError = (key, type, error) => {
  loggerPlugin.error({
    msg: 'SETTING_STORAGE_FETCH_ERROR',
    key,
    type,
    error,
  });
};

/**
 * @typedef {"string"|"bool"|"number"|"json"} SettingType
 */

/**
 * @param {{key: string, type: SettingType, defaultVal: any}} payloadSetting
 * @returns
 */
export const apiLocalSetting = (payloadSetting) => {
  if (!payloadSetting) {
    throw new Error('Setting payload is required');
  }

  const { key, type, defaultVal } = payloadSetting;

  if (!key) {
    throw new Error('Setting key is required');
  }

  if (!type) {
    throw new Error('Setting type is required');
  }

  if (typeof defaultVal === 'undefined') {
    throw new Error('Setting default value is required');
  }

  let loadedValue;

  const isUseLocalStorage = checkLocalStorageAvailable();

  if (!isUseLocalStorage) {
    storageGet(key)
      .then((value) => {
        loadedValue = value;
      })
      .catch((error) => {
        handleStorageGetError(key, type, error);
      });
  }

  const get = () => {
    if (!isUseLocalStorage) {
      if (typeof loadedValue === 'undefined') {
        return defaultVal;
      }
      return parseValueGet(loadedValue, type, defaultVal);
    }

    const value = localStorage.getItem(key);
    return parseValueGet(value, type, defaultVal);
  };

  const set = (value) => {
    const setValue = parseValueSet(value, type);

    if (isUseLocalStorage) {
      localStorage.setItem(key, setValue);
    }

    storageSet(key, setValue).catch(() => {});
    return setValue;
  };

  const remove = () => {
    if (isUseLocalStorage) {
      localStorage.removeItem(key);
    }
    storageRemove(key).catch(() => {});
    return true;
  };

  const getSync = async () => {
    if (isUseLocalStorage) {
      return get();
    }

    const value = await storageGet(key);
    return parseValueGet(value, type, defaultVal);
  };

  return {
    isUseLocalStorage,
    key,
    defaultVal,
    type,
    useStorage() {
      return useStorage(key, defaultVal);
    },
    get,
    reset() {
      return set(defaultVal);
    },
    set,
    remove,
    getSync,
  };
};

export const clearAllSetting = () => {
  localStorage.clear();
  return storageClear();
};
