using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using RebootKit.Engine.Foundation;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;

namespace RebootKit.Engine.Services.Simulation {
    public class WorldService : IService {
        private WorldConfig _config;
        private List<Actor> _actors = new();

        public async UniTask OnInit(CancellationToken cancellationToken) {
            await UniTask.Yield(cancellationToken);
        }

        public void Dispose() {
            KillAllActors();
        }

        public async UniTask Load(WorldConfig worldConfig) {
            _config = worldConfig;

            AsyncOperationHandle<SceneInstance> handle = worldConfig.MainScene.LoadSceneAsync(LoadSceneMode.Additive);
            await handle.ToUniTask();
            SceneManager.SetActiveScene(handle.Result.Scene);
        }

        public async UniTask<TActor> SpawnActor<TActor>(AssetReferenceT<GameObject> asset, CancellationToken cancellationToken) where TActor : Actor {
            GameObject gameObject = await Addressables.InstantiateAsync(asset);
            if (cancellationToken.IsCancellationRequested) {
                asset.ReleaseInstance(gameObject);
                return null;
            }

            if (gameObject.TryGetComponent(out TActor actor)) {
                return actor;
            }

            asset.ReleaseInstance(gameObject);
            return null;
        }

        public async UniTask RegisterActor(Actor actor) {
            _actors.Add(actor);
            await UniTask.Yield();
        }

        public void KillActor(Actor actor) {
            Addressables.ReleaseInstance(actor.gameObject);
        }

        public void KillAllActors() {
            foreach (Actor actor in _actors) {
                Addressables.ReleaseInstance(actor.gameObject);
            }

            _actors.Clear();
        }
    }
}