using Framework.Entities;
using Framework.InteractionSystem;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace Project.World
{
    public class WorldLoader : CoreBehaviour
    {
        public class AddLoadableAction : CoreAction
        {
            public Loadable loadable;
            
            public AddLoadableAction(Loadable loadable)
            {
                this.loadable = loadable;
            }
        }

        public class LoadFromPositionAction : CoreAction
        {
            public Vector3 position;
            public float range;

            public LoadFromPositionAction(Vector3 position, float range)
            {
                this.position = position;
                this.range = range;
            }
        }

        public class UnloadAllAtRandomAction : CoreAction{}
        public class FinishedUnloadingAllAction : CoreAction { }

        private List<Loadable> loadables;
        private bool unloadAllAtRandom = false;

        // Use this for initialization
        protected override void InnerAwake()
        {
            this.loadables = new List<Loadable>();

            ActionMediatorLocator.Get().Subscribe<AddLoadableAction>(this);
            AddActionHandler<AddLoadableAction>(AddLoadable);
            ActionMediatorLocator.Get().Subscribe<LoadFromPositionAction>(this);
            AddActionHandler<LoadFromPositionAction>(LoadFromPosition);
            ActionMediatorLocator.Get().Subscribe<UnloadAllAtRandomAction>(this);
            AddActionHandler<UnloadAllAtRandomAction>(UnloadAllAtRandom);
        }

        // Update is called once per frame
        protected override void InnerUpdate()
        {
            if (this.unloadAllAtRandom)
            {
                this.unloadAllAtRandom = false;
                StartCoroutine("UnloadRandomRoutine");
            }
        }

        private void AddLoadable(AddLoadableAction action)
        {
            this.loadables.Add(action.loadable);
        }

        private void LoadFromPosition(LoadFromPositionAction action)
        {
            loadables.Where(i => Vector3.Distance(i.GetStartPosition(), action.position) < action.range).ToList().ForEach(i => i.SetLoaded(true));
        }

        private void UnloadAllAtRandom(UnloadAllAtRandomAction action)
        {
            this.unloadAllAtRandom = true;
        }

        private IEnumerator UnloadRandomRoutine()
        {
            List<Loadable> randomisedLoadables = this.loadables.Where(i => i.loaded == true).ToList();
            for (int i = 0; i < randomisedLoadables.Count; i++)
            {
                Loadable temp = randomisedLoadables[i];
                int randomIndex = UnityEngine.Random.Range(i, randomisedLoadables.Count);
                randomisedLoadables[i] = randomisedLoadables[randomIndex];
                randomisedLoadables[randomIndex] = temp;
            }

            for (int i = 0; i < randomisedLoadables.Count; i++)
            {
                randomisedLoadables[i].SetLoaded(false);
                if (i % 5 == 0)
                {
                    yield return null;
                }
            }
            Announce(new FinishedUnloadingAllAction());
        }
    }
}
