import { omitBy } from 'lodash';

interface WrapValue<T> {
  value: T;
  [key: string]: any;
}

type PartialWrapValue<T> = {
  [P in keyof T]: WrapValue<T[P]>;
};
interface IUserStorage {
  id?: number;
  token?: string;
}

type IUserInfoKey = keyof PartialWrapValue<IUserStorage>;

class SDKStorage {
  id = '';

  userInfo: PartialWrapValue<IUserStorage> = {};

  loaded = false;

  constructor(id: string) {
    this.id = id;
    const userInfo = localStorage.getItem(id);
    if (userInfo) {
      try {
        this.userInfo = JSON.parse(userInfo);
        for (const key in this.userInfo) {
          const keyValue = this.userInfo[key as IUserInfoKey];
          if (!(keyValue instanceof Object) && keyValue) {
            this.userInfo[key as IUserInfoKey] = {
              value: keyValue,
            };
            continue;
          }
          if (keyValue && keyValue.timeStamp && keyValue.date) {
            const time = Date.now();
            if (time - keyValue.date > keyValue.timeStamp * 1000) {
              this.removeItem(key as IUserInfoKey);
            }
          }
        }
      } catch (err) {
        console.error('The localStorage is occupied, please clear it first');
      }
    } else {
      this.userInfo = { id: { value: +id } };
      localStorage.setItem(id, JSON.stringify(this.userInfo));
    }
    this.loaded = true;
  }

  static unRefValue(user: PartialWrapValue<IUserStorage>) {
    const obj = {} as Record<IUserInfoKey, any>;
    for (const key in user) {
      const value = user[key as IUserInfoKey]?.value;
      if (value) {
        obj[key as IUserInfoKey] = value;
      }
    }
    return obj;
  }

  static getUserToken(uid: string | undefined | null) {
    if (uid) {
      const userInfo = localStorage.getItem(uid);
      if (userInfo) {
        try {
          const data = JSON.parse(userInfo);
          const tokenValue = data['token'];
          return tokenValue?.value;
        } catch (e) {
          console.error('The localStorage is occupied, please clear it first');
          return '';
        }
      }
    }
    return '';
  }

  setItem(key: IUserInfoKey, value: any, opt: { timeStamp?: number } = {}) {
    this.userInfo[key] = omitBy(
      {
        value,
        timeStamp: opt.timeStamp,
        date: opt.timeStamp ? Date.now() : undefined,
      },
      (value) => value === null || value === undefined,
    ) as WrapValue<any>;
    localStorage.setItem(this.id, JSON.stringify(this.userInfo));
  }

  getItem(key: IUserInfoKey) {
    if (this.userInfo[key]) {
      return this.userInfo[key]!.value;
    }
    return undefined;
  }

  removeItem(key: IUserInfoKey) {
    this.userInfo[key] = undefined;
    localStorage.setItem(this.id, JSON.stringify(this.userInfo));
  }

  clear() {
    const { id } = this.userInfo;
    this.userInfo = {
      id,
    };
    localStorage.setItem(this.id, JSON.stringify(this.userInfo));
  }

  clearAll() {
    this.userInfo = {};
    localStorage.removeItem(this.id);
  }
}

export default SDKStorage;
