local ____lualib = require("lualib_bundle")
local WeakMap = ____lualib.WeakMap
local __TS__New = ____lualib.__TS__New
local Set = ____lualib.Set
local __TS__ObjectAssign = ____lualib.__TS__ObjectAssign
local __TS__ArrayIsArray = ____lualib.__TS__ArrayIsArray
local __TS__Generator = ____lualib.__TS__Generator
local __TS__ArrayMap = ____lualib.__TS__ArrayMap
local __TS__Class = ____lualib.__TS__Class
local __TS__ClassExtends = ____lualib.__TS__ClassExtends
local __TS__SetDescriptor = ____lualib.__TS__SetDescriptor
local __TS__Iterator = ____lualib.__TS__Iterator
local ____exports = {}
local cleanupFrames, reconcileChildren, instantiate, createComponent, updateContexts, childrenAsNodes, functionalComponentClasses, isClass, scheduledUpdates, flushingScheduledUpdates
local ____adapter = require("adapter")
local adapter = ____adapter.adapter
local ____common = require("utils.common")
local isLua = ____common.isLua
local TEXT_ELEMENT = ____common.TEXT_ELEMENT
local ____arrays = require("utils.arrays")
local getLength = ____arrays.getLength
local ____context = require("hooks.context")
local hooks = ____context.hooks
function ____exports.reconcile(parentFrame, instance, vnode, contexts)
    if contexts == nil then
        contexts = ____instance_component_contexts_0 or ({})
    end
    if not instance then
        if not vnode then
            return nil
        end
        return instantiate(vnode, parentFrame, contexts)
    elseif not vnode then
        cleanupFrames(instance)
        return nil
    elseif instance.vnode.type ~= vnode.type then
        local newInstance = instantiate(vnode, parentFrame, contexts)
        cleanupFrames(instance)
        return newInstance
    else
        local instanceOfSameType = instance
        local component = instanceOfSameType.component
        if type(vnode.type) == "string" then
            adapter:updateFrameProperties(instance.hostFrame, instance.vnode.props, vnode.props)
            instanceOfSameType.childInstances = reconcileChildren(instanceOfSameType, contexts, vnode.props.children)
        elseif component then
            if parentFrame then
                instanceOfSameType.hostFrame = parentFrame
            end
            component.props = vnode.props
            contexts = updateContexts(contexts, component)
            do
                local function ____catch(err)
                    print(err)
                    cleanupFrames(instance)
                    error(err, 0)
                end
                local ____try, ____hasReturned = pcall(function()
                    hooks.beforeRender(component)
                end)
                if not ____try then
                    ____catch(____hasReturned)
                end
            end
            local children = component:render(vnode.props, contexts)
            do
                local function ____catch(err)
                    if component.componentDidCatch then
                        component:componentDidCatch(err)
                    else
                        error(err, 0)
                    end
                end
                local ____try, ____hasReturned = pcall(function()
                    instanceOfSameType.childInstances = reconcileChildren(instanceOfSameType, contexts, children)
                end)
                if not ____try then
                    ____catch(____hasReturned)
                end
            end
        end
        instanceOfSameType.vnode = vnode
        return instanceOfSameType
    end
end
function cleanupFrames(instance)
    if instance.component then
        hooks.beforeUnmount(instance.component)
    end
    if instance.childInstances then
        for ____, child in ipairs(instance.childInstances) do
            if child ~= nil then
                cleanupFrames(child)
            end
        end
    end
    if instance.hostFrame and not instance.component then
        adapter:cleanupFrame(instance.hostFrame)
    end
    scheduledUpdates:delete(instance)
    flushingScheduledUpdates:delete(instance)
end
function reconcileChildren(instance, contexts, children)
    local hostFrame = instance.hostFrame
    local childInstances = instance.childInstances
    local newChildInstances = {}
    local flatChildren = childrenAsNodes(children)
    local count = math.max(#childInstances, #flatChildren)
    do
        local i = 0
        while i < count do
            local childInstance = childInstances[i + 1]
            local childNode = flatChildren[i + 1]
            local newChildInstance = ____exports.reconcile(hostFrame, childInstance, childNode, contexts)
            if newChildInstance ~= nil then
                newChildInstances[#newChildInstances + 1] = newChildInstance
            end
            i = i + 1
        end
    end
    return newChildInstances
end
function instantiate(vnode, parentFrame, contexts)
    local ____vnode_6 = vnode
    local ____type = ____vnode_6.type
    local props = ____vnode_6.props
    if type(____type) == "string" then
        local frame = adapter:createFrame(____type, parentFrame, props)
        local childNodes = childrenAsNodes(vnode.props.children)
        local childInstances = __TS__ArrayMap(
            childNodes,
            function(____, child) return instantiate(child, frame, contexts) end
        )
        return {hostFrame = frame, vnode = vnode, childInstances = childInstances}
    else
        local instance = {vnode = vnode, hostFrame = parentFrame, childInstances = {}}
        instance.component = createComponent(vnode, instance, contexts)
        contexts = updateContexts(contexts, instance.component)
        do
            local function ____catch(err)
                print(err)
            end
            local ____try, ____hasReturned = pcall(function()
                hooks.beforeRender(instance.component)
            end)
            if not ____try then
                ____catch(____hasReturned)
            end
        end
        local children = childrenAsNodes(instance.component:render(props, contexts))
        do
            local function ____catch(err)
                if instance.component.componentDidCatch then
                    instance.component:componentDidCatch(err)
                else
                    error(err, 0)
                end
            end
            local ____try, ____hasReturned = pcall(function()
                instance.childInstances = __TS__ArrayMap(
                    children,
                    function(____, child) return instantiate(child, parentFrame, contexts) end
                )
            end)
            if not ____try then
                ____catch(____hasReturned)
            end
        end
        return instance
    end
end
function createComponent(vnode, instance, contexts)
    local ____vnode_7 = vnode
    local ComponentType = ____vnode_7.type
    local props = ____vnode_7.props
    local constructor
    if type(ComponentType) == "string" then
        error("Tried to createComponent() with string", 0)
    elseif isClass(ComponentType) then
        constructor = ComponentType
    else
        local renderFunc = ComponentType
        local existingClass = functionalComponentClasses:get(renderFunc)
        if existingClass then
            constructor = existingClass
        else
            local ____class_8 = __TS__Class()
            ____class_8.name = ____class_8.name
            __TS__ClassExtends(____class_8, ____exports.ClassComponent)
            function ____class_8.prototype.render(self, props, contexts)
                return renderFunc(props, contexts)
            end
            constructor = ____class_8
            functionalComponentClasses:set(renderFunc, constructor)
        end
    end
    local component = __TS__New(constructor, props)
    component.contexts = contexts
    component.instance = instance
    return component
end
local containerMap = __TS__New(WeakMap)
function ____exports.render(vnode, container)
    local prevInstance = containerMap:get(container) or nil
    local nextInstance = ____exports.reconcile(container, prevInstance, vnode)
    containerMap:set(container, nextInstance)
end
local ____instance_component_2 = instance
if ____instance_component_2 ~= nil then
    ____instance_component_2 = ____instance_component_2.component
end
local ____instance_component_contexts_0 = ____instance_component_2
if ____instance_component_contexts_0 ~= nil then
    ____instance_component_contexts_0 = ____instance_component_contexts_0.contexts
end
updateContexts = function(contexts, component)
    local context = component.constructor.context
    if context ~= nil then
        contexts = __TS__ObjectAssign({}, contexts, {[context.id] = component})
    end
    return contexts
end
local function isRecord(value)
    return not not value and type(value) == "table"
end
local function isChild(value)
    if type(value) == "string" then
        return true
    end
    if not isRecord(value) then
        return false
    end
    local ____temp_5 = type(value.type) ~= "string" and type(value.type) ~= "function"
    if ____temp_5 then
        local ____isLua_4
        if isLua then
            ____isLua_4 = not isRecord(value.type) or not isRecord(value.type.prototype)
        else
            ____isLua_4 = true
        end
        ____temp_5 = ____isLua_4
    end
    if ____temp_5 then
        return false
    end
    if not isRecord(value.props) then
        return false
    end
    return true
end
local childIterator
childIterator = __TS__Generator(function(children)
    if not __TS__ArrayIsArray(children) then
        if isChild(children) then
            coroutine.yield(children)
        end
        return
    end
    local length = getLength(children)
    do
        local i = 0
        while i < length do
            local itr = childIterator(children[i + 1])
            local cur = itr:next()
            while not cur.done do
                coroutine.yield(cur.value)
                cur = itr:next()
            end
            i = i + 1
        end
    end
end)
local function createTextElement(nodeValue)
    return {type = TEXT_ELEMENT, props = {nodeValue = nodeValue}}
end
childrenAsNodes = function(children)
    local arr = {}
    local itr = childIterator(children)
    local cur = itr:next()
    while not cur.done do
        arr[#arr + 1] = type(cur.value) == "string" and createTextElement(cur.value) or cur.value
        cur = itr:next()
    end
    return arr
end
functionalComponentClasses = __TS__New(WeakMap)
isClass = function(constructor)
    if isLua then
        return type(constructor) ~= "function"
    else
        return constructor.prototype ~= nil
    end
end
local instanceMap = __TS__New(WeakMap)
scheduledUpdates = __TS__New(Set)
____exports.scheduleUpdate = function(instance)
    scheduledUpdates:add(instance)
    adapter:scheduleUpdate()
end
____exports.ClassComponent = __TS__Class()
local ClassComponent = ____exports.ClassComponent
ClassComponent.name = "ClassComponent"
function ClassComponent.prototype.____constructor(self, props)
    self.props = props
    self.state = {}
    self.contexts = {}
end
__TS__SetDescriptor(
    ClassComponent.prototype,
    "instance",
    {
        get = function(self)
            return instanceMap:get(self)
        end,
        set = function(self, instance)
            instanceMap:set(self, instance)
        end
    },
    true
)
function ClassComponent.prototype.setState(self, partialState)
    self.state = __TS__ObjectAssign({}, self.state, partialState)
    local instance = instanceMap:get(self)
    if instance then
        ____exports.scheduleUpdate(instance)
    end
end
local function updateInstance(internalInstance)
    local vnode = internalInstance.vnode
    ____exports.reconcile(nil, internalInstance, vnode)
end
flushingScheduledUpdates = __TS__New(Set)
____exports.flushUpdates = function()
    flushingScheduledUpdates = __TS__New(
        Set,
        scheduledUpdates:values()
    )
    scheduledUpdates:clear()
    for ____, instance in __TS__Iterator(flushingScheduledUpdates) do
        if flushingScheduledUpdates:has(instance) then
            updateInstance(instance)
        end
    end
end
____exports.test = {functionalComponentClasses = functionalComponentClasses}
return ____exports
