import invariant from "@octetstream/invariant"
import isObject from "lodash/isObject"

import deprecate from "lib/helper/decorator/deprecate"

class ObjectIterator {
  constructor(iterable) {
    invariant(
      iterable && isObject(iterable) === false, TypeError,

      "Iterable must be an object."
    )

    this.__iterable = iterable

    // I'm using this method because of fucking semicolon -_-
    Array.from([Symbol.iterator, "keys", "values", "entries"])
      .forEach(name => this[name] = this[name].bind(this))
  }

  keys() {
    if (!this.__iterable) {
      return []
    }

    return Object.keys(this.__iterable)
  }

  * values() {
    for (const [, value] of this.entries()) {
      yield value
    }
  }

  * entries() {
    for (const key of this.keys()) {
      const value = this.__iterable[key]

      yield [key, value]
    }
  }

  [Symbol.iterator]() {
    return this.values()
  }
}

const objectIterator = (iterable, entries = false) => {
  if (entries) {
    console.warn(
      "The \"entries\" flag is deprecated. "
        + "Use objectIterator(iterable).entries() instead."
    )

    return new ObjectIterator(iterable).entries()
  }

  return new ObjectIterator(iterable)
}

const keys = iterable => new ObjectIterator(iterable).keys()

const values = iterable => new ObjectIterator(iterable).values()

const entries = iterable => new ObjectIterator(iterable).entries()

objectIterator.keys = keys |> deprecate(
  "Use objectIterator(iterable).keys() instead."
)

objectIterator.values = values |> deprecate(
  "Use objectIterator(iterable).values() instead."
)

objectIterator.entries = entries |> deprecate(
  "Use objectIterator(iterable).entries() instead"
)

export default objectIterator
export {keys, values, entries}

@@ -87,25 +87,21 @@
 %0Aimport 
-deprecate
+proxy
  from %22l
@@ -124,19 +124,86 @@
 tor/
-deprecate%22%0A
+proxy%22%0Aimport apply from %22lib/helper/proxy/selfInvokingClass%22%0A%0A@proxy(%7Bapply%7D)
 %0Acla
@@ -228,19 +228,19 @@
 %7B%0A  
-constructor
+static keys
 (ite
@@ -256,152 +256,244 @@
     
-invariant(%0A      iterable && isObject(iterable) === false, TypeError,%0A%0A      %22Iterable must be an object.%22%0A    )%0A%0A    this.__iterable = 
+return new ObjectIterator(iterable).keys()%0A  %7D%0A%0A  static values(iterable) %7B%0A    return new ObjectIterator(iterable).values()%0A  %7D%0A%0A  static entries(iterable) %7B%0A    return new ObjectIterator(iterable).entries()%0A  %7D%0A%0A  constructor(
 iterable
 %0A%0A  
@@ -492,193 +492,149 @@
 able
-%0A
+) %7B
 %0A    
-// I'm using this method because of fucking semicolon -_-%0A    Array.from(%5BSymbol.iterator, %22keys%22, %22values%22, %22entries%22%5D)%0A      .forEach(name =%3E this%5Bname%5D = this%5Bname%5D.bind(this))
+if (iterable && !isObject(iterable)) %7B%0A      throw new TypeError(%22Iterable must be an object.%22)%0A    %7D%0A%0A    this.__iterable = iterable
 %0A  %7D
@@ -1023,853 +1023,164 @@
 %0A%7D%0A%0A
-const objectIterator = (iterable, entries = false) =%3E %7B%0A  if (entries) %7B%0A    console.warn(%0A      %22The %5C%22entries%5C%22 flag is deprecated. %22%0A        + %22Use objectIterator(iterable).entries() instead.%22%0A    )%0A%0A    return new ObjectIterator(iterable).entries()%0A  %7D%0A%0A  return new ObjectIterator(iterable)%0A%7D%0A%0Aconst keys = iterable =%3E new ObjectIterator(iterable).keys()%0A%0Aconst values = iterable =%3E new ObjectIterator(iterable).values()%0A%0Aconst entries = iterable =%3E new ObjectIterator(iterable).entries()%0A%0AobjectIterator.keys = keys %7C%3E deprecate(%0A  %22Use objectIterator(iterable).keys() instead.%22%0A)%0A%0AobjectIterator.values = values %7C%3E deprecate(%0A  %22Use objectIterator(iterable).values() instead.%22%0A)%0A%0AobjectIterator.entries = entries %7C%3E deprecate(%0A  %22Use objectIterator(iterable).entries() instead%22%0A)%0A%0Aexport default objectIterator%0Aexport %7Bkeys, values, 
+export default ObjectIterator%0Aexport const keys = ObjectIterator.keys%0Aexport const values = ObjectIterator.values%0Aexport const entries = ObjectIterator.
 entries
-%7D
 %0A

Rewrite object iterator.