local XLuaUtil = require("XLua/util.lua")
local CoroutineHelper = {}

CoroutineHelper._CS_SCoroutineRunner_Component = nil

-- Just give a lua function.
-- You can call like this: coroutine.yield(CS.UnityEngine.WaitForSeconds(3))
-- Or you can call CoroutineHelper.Wait(3) for short.
function CoroutineHelper:Start(...)
    print("CoroutineHelper.Start ... ... ")
    local luaRoot = CS.UnityEngine.GameObject.Find("LuaRoot")
    assert(luaRoot ~= nil)
    local coroutineHolder = luaRoot.transform:Find("coroutineHolder")
    if not coroutineHolder then
        coroutineHolder = CS.UnityEngine.GameObject("coroutineHolder")
        coroutineHolder.transform:SetParent(luaRoot.transform)
        self._CS_SCoroutineRunner_Component = coroutineHolder:AddComponent(typeof(CS.SFramework.SCoroutineRunner))
    end

    assert(CoroutineHelper._CS_SCoroutineRunner_Component ~= nil, "SCoroutineRunner is not exised!")
    return CoroutineHelper._CS_SCoroutineRunner_Component:StartCoroutine(XLuaUtil.cs_generator(...))
end

function CoroutineHelper:Stop(targetCoroutine)
    print("CoroutineHelper.Stop ... ... ")
    assert(self._CS_SCoroutineRunner_Component ~= nil, "SCoroutineRunner is not exised!")
    if targetCoroutine then
        self._CS_SCoroutineRunner_Component:StopCoroutine(targetCoroutine)
    end
end

function CoroutineHelper:CoroutineCall(func)
    return function(...)
        local co = coroutine.create(func)
        assert(coroutine.resume(co, ...))
    end
end

function CoroutineHelper:Wait(seconds)
    coroutine.yield(CS.UnityEngine.WaitForSeconds(seconds))
end

function CoroutineHelper:WaitForEndOfFrame()
    coroutine.yield(CS.UnityEngine.WaitForEndOfFrame())
end

function CoroutineHelper:WaitSendWebRequest(luaRequest)
    coroutine.yield(luaRequest:SendWebRequest())
end

function CoroutineHelper:Test()
    local targetCoroutine = CoroutineHelper.Start(
        function()
            print("Test Co a Start ... ...")
            
            coroutine.yield(CoroutineHelper.Start(function()
                print("Test Co b started inside coroutine a")
                coroutine.yield(CS.UnityEngine.WaitForSeconds(2))
                print("Co b Run in Co a")
            end))

            while true do 
                coroutine.yield(CS.UnityEngine.WaitForSeconds(1))
                print("Test Co a alive ... ...")
            end
        end
    )

    CoroutineHelper.Start(
        function()
            print("Test Co c Start ... ... close Co a after 8 seconds")
            coroutine.yield(CS.UnityEngine.WaitForSeconds(8))
            CoroutineHelper.Stop(targetCoroutine)
            print("Close Co a By Co c ... ...")
        end
    )
end

return CoroutineHelper
