import Baobab from 'baobab'
import { BaseModel } from 'cerebral/internal'

export default class BaobabModelFactory {
  constructor(baobabOptions = {}) {
    class BaobabModel extends BaseModel {
      constructor(controller) {
        super(controller)
        this.state = new Baobab(this.initialState)
      }
      get(path = []) {
        return this.state.get(path)
      }
      set(path, value) {
        this.state.set(path, value)
        this.changedPaths.push({
          forceChildPathUpdates: true,
          path,
        })
      }
      toggle(path) {
        this.state.set(path, !this.state.get(path))
        this.changedPaths.push({
          path,
        })
      }
      push(path, value) {
        this.state.push(path, value)
        this.changedPaths.push({
          path,
        })
      }
      merge(path, ...values) {
        if (!this.state.exists(path)) {
          this.state.set(path, {})
        }
        values.forEach(value => {
          this.state.merge(path, value)
          for (let prop in value) {
            this.changedPaths.push({
              forceChildPathUpdates: true,
              path: path.concat(prop),
            })
          }
        })
      }
      pop(path) {
        this.state.pop(path)
        this.changedPaths.push({
          path,
        })
      }
      shift(path) {
        this.state.shift(path)
        this.changedPaths.push({
          path,
        })
      }
      unshift(path, value) {
        this.state.unshift(path, value)
        this.changedPaths.push({
          path,
        })
      }
      splice(path, ...args) {
        this.state.splice(path, args)
        this.changedPaths.push({
          path,
        })
      }
      unset(path) {
        this.state.unset(path)
        this.changedPaths.push({
          forceChildPathUpdates: true,
          path,
        })
      }
      concat(path, value) {
        this.state.concat(path, value)
        this.changedPaths.push({
          path,
        })
      }
    }

    return BaobabModel
  }
}
