using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using JetBrains.Annotations;

namespace RebootKit.Engine.Foundation {
    public interface IController : IDisposable {
        UniTask OnStart(CancellationToken cancellationToken);
        void OnStop();
        void OnTick();
    }

    public class ControllersManager<TController> : IDisposable where TController : IController {
        readonly CancellationToken _cancellationToken;
        readonly List<TController> _controllers = new List<TController>();
        bool _isRunning;

        public ControllersManager(CancellationToken cancellationToken) {
            _cancellationToken = cancellationToken;
        }

        public void Dispose() {
            foreach (TController controller in _controllers) {
                controller.Dispose();
            }
        }

        public T Get<T>() where T : class, IController {
            foreach (TController controller in _controllers) {
                if (controller is T res) {
                    return res;
                }
            }

            return null;
        }

        public bool TryFind<T>(out T outController) where T : IController {
            foreach (TController controller in _controllers) {
                if (controller is T res) {
                    outController = res;
                    return true;
                }
            }

            outController = default;
            return false;
        }

        public void Add(TController controller) {
            _controllers.Add(controller);

            if (_isRunning) {
                controller.OnStart(_cancellationToken);
            }
        }

        public void Remove(TController controller) {
            if (_isRunning) {
                controller.OnStop();
            }

            _controllers.Remove(controller);
        }

        public async UniTask Start(CancellationToken cancellationToken) {
            if (_isRunning) {
                return;
            }

            foreach (TController controller in _controllers) {
                await controller.OnStart(cancellationToken);
            }

            _isRunning = true;
        }

        public void Stop() {
            if (!_isRunning) {
                return;
            }

            foreach (TController controller in _controllers) {
                controller.OnStop();
            }

            _isRunning = false;
        }

        public void Tick() {
            foreach (TController controller in _controllers) {
                controller.OnTick();
            }
        }
    }

    public static class ControllersManagerUtils {
        public static void Add(this ControllersManager<IController> manager, ControllerAsset asset) {
            IController controller = asset.Create();
            manager.Add(controller);
        }

        public static void Add(this ControllersManager<IController> manager, List<ControllerAsset> controllerAsset) {
            foreach (ControllerAsset asset in controllerAsset) {
                IController controller = asset.Create();
                manager.Add(controller);
            }
        }

        public static void Add(this ControllersManager<IController> manager, ControllerAsset[] controllerAsset) {
            foreach (ControllerAsset asset in controllerAsset) {
                IController controller = asset.Create();
                manager.Add(controller);
            }
        }
    }
}