import { AsyncAuthAjax } from "../controller/Ajax";
import { API } from "../dict/Consts";

let latest, STORE_VERSION = 'v0.4';
const store = new Store(latest = {
  _VERSION_: STORE_VERSION,
  'navigation': {
    current: 'Login'
  },
  loaded: {
    cards: false
  },
  'account': {
    userID: 5,
    name: 'Диогроген Курославович',
    phone: '79999877414',
  }
});

try{
  var data = JSON.parse( localStorage.getItem( 'store' ) );
  if(data._VERSION_ !== store.get('_VERSION_')){
    console.warn('STORE:outdated, new state → localStorage');
    console.warn('\tSTORE:currentData #'+ store.get('_VERSION_'), store._props);
    console.warn('\tSTORE:savedData #'+ STORE_VERSION, data);
    console.warn('\tSTORE:hint → Run Store.restore() for restore saved state');
    console.warn('\tStore:hint → Run Store.update() for load latest default state');

    Store.restore = function() {
      for( var k in data ){
        if(k !== '_VERSION_'){
          store.set( k, data[ k ] );
        }
      }
    };
    Store.update = function() {
      for( var k in latest ){
        if(k !== '_VERSION_'){
          store.set( k, latest[ k ] );
        }
      }
    };
  }else{
    for( var k in data ){
      store.set( k, data[ k ] );
    }
    console.log('STORE:loaded ← localStorage', data);

  }
}catch( e ){}
store.on('change', function() {
  localStorage.setItem('store', JSON.stringify(store._props));
});

const createSavableStore = function(name) {
  const store = new Store(latest = {
    _VERSION_: STORE_VERSION
  });
  try{
    var data = JSON.parse( localStorage.getItem( name ) );
    if(data._VERSION_ === store.get('_VERSION_')){
      for( var k in data ){
        store.set( k, data[ k ] );
      }
    }
  }catch( e ){}
  let shouldSave,
    saveFn = function() {
      localStorage.setItem(name, JSON.stringify(store._props));
      shouldSave = false;
    };
  store.on('change', function() {
    if(!shouldSave)
      shouldSave = setTimeout(saveFn, 500);
  });
  return store;
};

const cards = createSavableStore('cards');
//const products = createSavableStore('products');
const categories = createSavableStore('categories');

const SavableArray = function(name, length) {
  this.name = name;
  this.items = [];
  this.maxLength = length;
};
SavableArray.prototype = Object.assign({
  length: 0,
  push: function(item) {
    this.items.push(item);
    this.save();
    this.length++;
  },
  pop: function() {
    try{
      return this.items.pop();
    }finally{
      this.save();
    }
  },
  save: function() {
    localStorage.setItem(this.name, JSON.stringify({_VERSION_: STORE_VERSION, items: this.items}));
  },
  load: function(){

    try{
      var data = localStorage.getItem(this.name), parsed;
      parsed = JSON.parse(data);
      if(parsed._VERSION_ === STORE_VERSION){
        this.items = data.items;
        this.length = this.items.length;
      }
    }catch( e ){}


  }
});

const history = new SavableArray('history', 50);


const Model = {
  cards: cards,
  categories: categories,
  history: history
};

categories.loading = {};

const AsyncResourceLoaderQueue = function(cfg) {
  const loading = {};
  cfg = Object.assign({
    key: (a)=>a,
    arg: (a)=>a
  }, cfg);
  return async function() {
    let arg = await cfg.arg.apply(this, arguments),
        key = cfg.key.call(this, arg);

    if(cfg.checkExist.call(this, arg)){
      return cfg.getExisted.call(this, arg);
    }else if(loading[key]){
      return new Promise((resolve, reject)=>
        loading[key].push({resolve, reject}));
    }else{
      loading[key] = [];
      try{
        const result = await cfg.fetch.call(this, arg);

        loading[key].forEach((promise)=>{
          promise.resolve(result);
        });
        delete loading[key];
        return result;
      }catch(e){
        loading[key].forEach((promise)=>{
          promise.reject(e);
        });
        throw new Error(e)
      }
    }

  }
};
categories.load = AsyncResourceLoaderQueue({
  arg: (category)=>category+'',
  checkExist(category){
    return this.get(category) !== void 0
  },
  getExisted(category) {
    return this.get(category)
  },
  async fetch(category){
    const result = await AsyncAuthAjax.get( API.ENDPOINTS.CATEGORIES_CATEGORY( category ) );
    this.set(category, result);
    return result
  }
});
/*categories.load = async function(category) {
  return category+='';
};*/
cards.load = AsyncResourceLoaderQueue({
  async arg(category, id){
    const categoryInfo = await Model.categories.load(category);

    return {category, id, type: categoryInfo.type, key: [category,id].join('.')}
  },
  key: ({key})=>key,
  checkExist({key}){
    let item = this.get(key);
    if(item === void 0)
      return false;

    if(!item.detailed)
      return false;

    return true;
  },
  getExisted({key}) {
    return this.get(key)
  },
  async fetch( {category, id, type, key}){
    console.log(type)
    const result = await AsyncAuthAjax.get( API.ENDPOINTS[type===1?'GET_CARD_PRODUCTS_ITEM' : 'GET_CARD_INFO_CARD']( id ) );
    if(type!==1){
      result.items.map(item=>{item.seen = item.isView; delete item.isView});
    }

    const data = {...result, seen: result.isView, type: type, category_id: category, detailed: true};
    this.set(key, data);
    return data
  }
});

/*async function(category, id, cb) {
  const data = await categories.load(category);
  if(data.type)

  data.type
}*/
const tmpStore = new Store({
  loaded: false,
  navigation: {current: 'Login'},
  isMobile: false,
  width: window.innerWidth,
  newItemCount: 1000
});

let lastNav = null;
store.sub('navigation.current', function(val) {
  console.log('APP:navigation', lastNav,'→', val);
  lastNav = val;
});

window.store = store;
window.tmpStore = tmpStore;
window.Model = Model;