import { GET, POST, DELETE, FORM, PUT, STORE_UPDATE, STORE_LOADING, STORE_LOADED } from '../services/Constant';

const API_TOKEN = 'API_TOKEN';

export default class BaseStore {
  constructor({ key, local }) {
    this.key = key;
    this.local = local;
  }

  init(project, { Api, Cache, History }) {
    this.History = History;
    this.Api = Api;
    this.Cache = Cache;
    this.project = project;
    this.state = this.local ? Object.assign(this.initState(), this.getLocal(this.key) || {}) : this.initState();
  }

  initState() {
    return {};
  }

  setStore(store) {
    this.store = store;
    if (this.initAfter) this.initAfter();
  }

  setState(state) {
    if (!this.store) throw new Error('store init error');
    console.log('setState', state);
    this.store.dispatch({
      key: this.key,
      type: STORE_UPDATE,
      state,
    });
  }

  setToken(token) {
    this.saveLocal(API_TOKEN, token);
  }

  getToken() {
    return this.getLocal(API_TOKEN);
  }

  apiGet(url, data, loadOption) {
    return this.request({ url, method: GET }, data, loadOption);
  }

  apiPost(url, data, loadOption) {
    return this.request({ url, method: POST }, data, loadOption);
  }

  apiPut(url, data, loadOption) {
    return this.request({ url, method: PUT }, data, loadOption);
  }

  apiDel(url, data, loadOption) {
    return this.request({ url, method: DELETE }, data, loadOption);
  }

  apiForm(url, data, loadOption) {
    return this.request({ url, method: POST, type: FORM }, data, loadOption);
  }

  getRequestHeader() {
    const headers = [];
    if (this.project.apiToken) {
      headers.push({ key: this.project.apiToken, value: this.getToken() });
    }
    return headers.length === 0 ? null : headers;
  }

  request(api, data = {}) {
    this.requestBeforeHook();
    return this.Api.request(api.url, {
      method: api.method,
      data,
      type: api.type,
      headers: this.getRequestHeader(),
    })
      .then(body => {
        try {
          return this.requestBodyHandle(body);
        } catch (err) {
          throw err;
        }
      })
      .finally(() => {
        this.requestAfterHook();
      })
      .end(result => {
        if (__DEBUG__) console.log(result);
      });
  }

  loading() {
    if (!this.store) throw new Error('store init error');
    this.store.dispatch({
      type: STORE_LOADING,
    });
  }

  loaded() {
    if (!this.store) throw new Error('store init error');
    this.store.dispatch({
      type: STORE_LOADED,
    });
  }

  requestBeforeHook() {
    this.loading();
  }

  requestBodyHandle(body) {
    if (body.status === 200) return body.result;
    throw new Error(body.message);
  }

  requestAfterHook() {
    this.loaded();
  }

  getCacheKey(key) {
    return `store.${key}`;
  }

  getLocal(key) {
    return this.Cache.getCache(this.getCacheKey(key), true);
  }

  saveLocal(key, value) {
    this.Cache.setCache(this.getCacheKey(key), value, 86400 * 30, true);
  }

  removeLocal(key) {
    this.Cache.removeCache(this.getCacheKey(key), true);
  }

  getApiCache(key, api) {
    const result = this.Cache.getCache(key);
    if (result) return Promise.resolve(result);
    return api().then(data => {
      this.Cache.setCache(key, data);
    });
  }

  merge(state, action) {
    const _ = Object.assign({}, state, action.state);
    if (this.local) {
      setImmediate(() => {
        this.saveLocal(this.key, _);
      });
    }
    return _;
  }

  handle(state = this.state, action) {
    this.state = action.key === this.key ? this.merge(state, action) : state;
    return this.state;
  }
}
