// src/vuex/store.js
import { applyMixin } from './install'
import ModuleCollection from './module/module-collection'
import { forEachValue } from './utils'

export let Vue
const installModule = (store, path, module, rootState) => {
  // 将子模块的状态定义到根模块
  if (path.length > 0) {
    const parent = path.slice(0, -1).reduce((memo, current) => {
      return memo[current]
    }, rootState)
    // 这样添加的状态不是响应式的
    // parent[path[path.length - 1]] = module.state

    // 新增不存在的属性属性使用set,将其设置为响应式的
    Vue.set(parent, path[path.length - 1], module.state)
  }

  module.forEachMutation((mutation, key) => {
    store.mutations[key] = store.mutations[key] || []
    store.mutations[key].push((payload) => mutation.call(store, module.state, payload))
  })
  module.forEachAction((action, key) => {
    store.actions[key] = store.actions[key] || []
    store.actions[key].push((payload) => action.call(store, store, payload))
  })
  module.forEachChildren((childModule, key) => {
    installModule(store, path.concat(key), childModule, rootState)
  })
  module.forEachGetters((gettersFn, key) => {
    store.wrapGetters[key] = () => {
      return gettersFn.call(store, module.state)
    }
  })
}

function resetStoreVM(store, state) {
  const computed = {}
  forEachValue(store.wrapGetters, (fn, key) => {
    computed[key] = fn
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key]
    })
  })
  store._vm = new Vue({
    data: {
      $$state: state
    },
    computed
  })
}

export class Store {
  constructor(options) {
    // 可能用户会有嵌套的module
    this._modules = new ModuleCollection(options)
    console.log('ddd', this._modules)
    this.mutations = {} // 将用户所有模块的mutation都放到这个对象中
    this.actions = {} // 将用户所有模块的action放到这个对象中
    this.getters = {}
    
    this.wrapGetters = {} // 用于临时存放所有的getters
    const state = options.state // 获取用户状态

    // 将用户所有模块的 mutation、action、state、getters 都放到对象中
    installModule(this, [], this._modules.root, state)
    resetStoreVM(this, state)
    console.log('this.state', this.state)
    console.log('this.getters', this.getters)
    console.log('this.mutations', this.mutations)
    console.log('this.actions', this.actions)
  }
  get state() {
    return this._vm._data.$$state
  }
}

export const install = (_Vue) => {
  Vue = _Vue
  applyMixin(Vue)
}
// src/vuex/module/module-collection.js
import { forEachValue } from "../utils"
import Module from "./module"

export default class ModuleCollection {
  constructor(options) { // 遍历用户的属性对数据进行格式化
    this.root = null
    this.register([], options)
  }
  register(path, rootModule) {
    const newModule = new Module(rootModule)
    if (path.length == 0) {
      this.root = newModule
    }else {
      const parent = path.slice(0, -1).reduce((memo, current) => {
        // return memo._children[current]
        return memo.getChild(current)
      }, this.root)
      // parent._children[path[path.length - 1]] = newModule
      parent.addChild(path[path.length - 1], newModule)
    }
    // 检测是否配置了 modules 属性
    if (rootModule.modules) {
      forEachValue(rootModule.modules, (module, moduleName) => {
        this.register(path.concat(moduleName), module)
      })
    }
  }
}

用户

// src/vuex/module/module.js
import { forEachValue } from "../utils"

export default class Module {
  constructor(rawModule) {
    this._raw = rawModule
    this._children = {}
    this.state = rawModule.state
  }
  getChild(key) {
    return this._children[key]
  }
  addChild(key, module) {
    this._children[key] = module
  }
  forEachMutation(fn) {
    if (this._raw.mutations) { // 有mutation就遍历这个mutation
      forEachValue(this._raw.mutations, fn)
    }
  }
  forEachAction(fn) {
    if (this._raw.actions) { // 有action就遍历这个actions
      forEachValue(this._raw.actions, fn)
    }
  }
  forEachGetters(fn) {
    if (this._raw.getters) {
      forEachValue(this._raw.getters, fn)
    }
  }
  forEachChildren(fn) {
    forEachValue(this._children, fn)
  }
}