import { patch } from '../patch'

export const VUE_VIEW = '__vueVNodeRef__'

let tid = 0
export default {
  name: 'v-template',

  props: {
    name: {
      type: String
    },

    if: {
      type: String
    }
  },

  mounted() {
    if (!this.$scopedSlots.default) {
      return
    }

    this.$templates = this.$parent.$templates =
      this.$parent.$templates || new TemplateBag()
    this.$templates.registerTemplate(
      this.$props.name || (this.$props.if ? `v-template-${tid++}` : 'default'),
      this.$props.if,
      this.$scopedSlots.default
    )
  },

  render(h) {}
}

export class TemplateBag {
  constructor() {
    this._templateMap = new Map()
  }

  registerTemplate(name, condition, scopedFn) {
    this._templateMap.set(name, {
      condition,
      conditionFn: this.getConditionFn(condition),
      scopedFn,
      keyedTemplate: new VueKeyedTemplate(name, scopedFn)
    })
  }

  get selectorFn() {
    let self = this
    return function templateSelectorFn(item) {
      const iterator = self._templateMap.entries()
      let curr
      while ((curr = iterator.next().value)) {
        const [name, { conditionFn }] = curr
        if (conditionFn(item)) {
          return name
        }
      }
      return 'default'
    }
  }

  getConditionFn(condition) {
    return new Function('item', `return !!(${condition})`)
  }

  getKeyedTemplate(name) {
    const { keyedTemplate } = this._templateMap.get(name)
    return keyedTemplate
  }

  patchTemplate(name, context, oldVnode) {
    const { scopedFn } = this._templateMap.get(name)

    return patch(oldVnode, scopedFn(context)).nativeView
  }

  getAvailable() {
    return Array.from(this._templateMap.keys())
  }

  getKeyedTemplates() {
    return Array.from(this._templateMap.values()).map(
      ({ keyedTemplate }) => keyedTemplate
    )
  }
}

export class VueKeyedTemplate /* implements KeyedTemplate */ {
  constructor(key, scopedFn) {
    this._key = key
    this._scopedFn = scopedFn
  }

  get key() {
    return this._key
  }

  createView() {
    const vnode = this._scopedFn(deepProxy({}))
    const nativeView = patch(null, vnode).nativeView
    nativeView[VUE_VIEW] = vnode

    console.log('CREATE_NEW_VIEW')
    return nativeView
  }
}

function deepProxy(object, depth = 0) {
  return new Proxy(object, {
    get() {
      if (depth > 10) {
        throw new Error('deep proxy over 10 deep.')
      }
      return deepProxy({}, depth + 1)
    }
  })
}

@@ -306,16 +306,49 @@
 plates =
+ this.$el.parentNode.$templates =
  this.$p
@@ -1606,50 +1606,142 @@
     
-return patch(oldVnode, scopedFn(context)).
+const vnode = scopedFn(context)%0A    const nativeView = patch(oldVnode, vnode).nativeView%0A    nativeView%5BVUE_VIEW%5D = vnode%0A%0A    return 
 nati
@@ -2304,43 +2304,8 @@
 de%0A%0A
-    console.log('CREATE_NEW_VIEW')%0A
     
@@ -2463,18 +2463,17 @@
 or('deep
- p
+P
 roxy ove

Attach $templates property to plain elements too