export function patch(target, props) {
    return m(Patch, {target, ...props})
}

const hasOwn = {}.hasOwnProperty
const isEventKey = /^on(?!init|create|(?:before)?(?:update|remove)$)/

function Patch({attrs}) {
    function handler(event) {
        const onevent = attrs[`on${event.type}`]
        let result

        if (typeof onevent === "function") {
            result = onevent.call(event.currentTarget, event)
        } else if (typeof onevent.handleEvent === "function") {
            onevent.handleEvent(event)
        }

        if (event.redraw !== false) {
            m.redraw()
        }

        if (result === false) {
            event.preventDefault()
            event.stopPropagation()
        }
    }

    function oncreate({attrs}) {
        const target = attrs.target

        for (const key of Object.keys(attrs)) {
            if (isEventKey.test(key)) {
                target.addEventListener(key, handler, false)
            }
        }
    }

    function onremove({attrs}) {
        const target = attrs.target

        for (const key of Object.keys(attrs)) {
            if (isEventKey.test(key)) {
                target.removeEventListener(key, handler, false)
            }
        }
    }

    return {
        onbeforeupdate(vnode, old) {
            attrs = vnode.attrs
            if (vnode.attrs.target !== old.attrs.target) {
                onremove(old)
                oncreate(vnode)
            } else {
                const target = vnode.attrs.target

                for (const key of Object.keys(vnode.attrs)) {
                    if (
                        isEventKey.test(key) &&
                        !hasOwn.call(old.attrs, key)
                    ) {
                        target.addEventListener(key, handler, false)
                    }
                }
                for (const key of Object.keys(old.attrs)) {
                    if (
                        isEventKey.test(key) &&
                        !hasOwn.call(vnode.attrs, key)
                    ) {
                        target.removeEventListener(key, handler, false)
                    }
                }
            }
            // Nothing's actually rendered. Let's not waste our time with it.
            return false
        },
        view() {},
        oncreate,
        onremove,
    }
}