using System;
using System.Collections;
using NUnit.Framework.Internal;
using UnityEngine.TestRunner.NUnitExtensions.Runner;
using UnityEngine.TestTools.TestRunner;

namespace UnityEngine.TestTools.Utils
{
    internal class CoroutineRunner
    {
        private bool m_Running;
        private readonly MonoBehaviour m_Controller;
        private readonly UnityTestExecutionContext m_Context;
        private IEnumerator m_TestCoroutine;

        public CoroutineRunner(MonoBehaviour playmodeTestsController, UnityTestExecutionContext context)
        {
            m_Controller = playmodeTestsController;
            m_Context = context;
        }

        public IEnumerator HandleEnumerableTest(IEnumerator testEnumerator)
        {
            do
            {
                if (!m_Running)
                {
                    m_Running = true;
                    m_TestCoroutine = ExMethod(WrapEnumeratorForChecks(testEnumerator));
                    m_Controller.StartCoroutine(m_TestCoroutine);
                }
                if (m_Context.ExecutionStatus == TestExecutionStatus.StopRequested || m_Context.ExecutionStatus == TestExecutionStatus.AbortRequested)
                {
                    StopAllRunningCoroutines();
                    yield break;
                }
                yield return null;
            }
            while (m_Running);
        }

        private void StopAllRunningCoroutines()
        {
            if (m_TestCoroutine != null)
            {
                m_Controller.StopCoroutine(m_TestCoroutine);
            }
        }

        private IEnumerator ExMethod(IEnumerator e)
        {
            yield return m_Controller.StartCoroutine(e);
            m_Running = false;
        }

        private IEnumerator WrapEnumeratorForChecks(IEnumerator e)
        {
            while (e.MoveNext())
            {
                if (Application.isBatchMode && e.Current is WaitForEndOfFrame)
                {
                    m_Running = false;
                    throw new Exception("UnityTest yielded WaitForEndOfFrame, which is not evoked in batchmode.");
                }

                yield return e.Current;
            }
        }
    }
}
