import {
  removeLast,
  checkFrozen
} from './methods-utils'
import {freeze as f} from './creation'
import {doNew} from './creation-utils'
import {printObject} from './test-utils'

/*
  methods
 */

export function getIn (path, o, onlyFrozen) {
  const oo = o || this
  return path.reduce((value, key) =>
    value === undefined || value === null
      ? value
      : onlyFrozen
        ? checkFrozen(value[key]) ? value[key] : undefined
        : value[key]
  , oo)
}

export const checkPath = (keyPath, method, o) => {
  const oo = o || this
  if (getIn(keyPath, oo, true) === undefined) {
    const errorMsg = `Invalid keyPath ${keyPath}, ${method}, ${printObject(oo)}`
    throw new Error(errorMsg)
  }
  return true
}

export function set (key, value, o) {
  const oo = o || this
  if (key === undefined || key === null) return oo
  return f(Object.assign({}, oo, {[key]: value}))
}

export function setIn (keyPath, value, o) {
  const oo = f(o) || this
  checkPath(keyPath, 'setIn', oo)
  if (keyPath.length <= 1) return set(keyPath[0], value, oo)
  return doNew(keyPath).reverse()
    .reduce((partial, key, index) => {
      const partialPath = removeLast(keyPath, index + 1)
      return getIn(partialPath, oo).set(key, partial)
    }, value)
}

export function update (key, callback, o) {
  const oo = o || this
  return set(key, callback(oo[key]), oo)
}

export function updateIn (keyPath, callback, o) {
  const oo = o || this
  checkPath(keyPath, 'updateIn', oo)
  return setIn(
    keyPath,
    callback(getIn(keyPath, oo)),
    oo
  )
}

export function merge () {
  const ref = Array.isArray(this) ? [] : {}
  const args = Object.assign.apply(ref, arguments)
  const o = doNew(this)
  const oo = Object.assign({}, o, args)
  return f(oo)
}

export function remove (key, o) {
  const oo = doNew(o || this)
  if (Array.isArray(oo)) return f(oo).deleteAt(key)
  delete oo[key]
  return f(oo)
}

// export function createIn (keyPath, value, o) {
//   const oo = doNew(keyPath)
//     .reduce((acc, key, index) => {
//       keyPath.slice(1).length === 1
//         ? set(key, value, acc)
//         : acc[key]
//     },
//       o
//     )
//   return f(oo)
// }

@@ -136,49 +136,8 @@
 ils'
-%0Aimport %7BprintObject%7D from './test-utils'
 %0A%0A/*
@@ -609,28 +609,8 @@
 hod%7D
-, $%7BprintObject(oo)%7D
 %60%0A  

remove print object from error message