using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Linq;
using ScenarioFlow;
using ScenarioFlow.Scripts.SFText;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using UnityEngine;

namespace HowToChooseTokenCode
{
	public class ShapeAnimator : MonoBehaviour, IReflectable
	{
		[SerializeField]
		private GameObject[] shapes;

		private Dictionary<string, GameObject> shapeDictionary;

		private static readonly float LeftX = -5.0f;
		private static readonly float RightX = 5.0f;
		private static readonly float Duration = 2.0f;
		private static readonly float Velocity = Mathf.Abs(LeftX - RightX) / Duration;

		private void Start()
		{
			shapeDictionary = shapes.ToDictionary(x => x.name, x => x);
			MoveAllShapesToLeft();
		}

		[CommandMethod("Move all shapes to left")]
		[Category("Shape Animation")]
		[Description("Move all the shpaes to left. Use this to reset the positions.")]
		[Snippet("Move all shapes to left")]
		public void MoveAllShapesToLeft()
		{
			foreach (var shape in shapes)
			{
				shape.transform.position = new Vector3(LeftX, shape.transform.position.y, shape.transform.position.z);
			}
		}

		[CommandMethod("move shape to right async")]
		[Category("Shape Animation")]
		[Description("Move the specified shape to right.")]
		[Snippet("Move {${1:name}} to right")]
		public async UniTask MoveShapeToRightAsync(string shapeName, CancellationToken cancellationToken)
		{
			if (shapeDictionary.TryGetValue(shapeName, out var shape))
			{
				try
				{
					await UniTaskAsyncEnumerable.EveryUpdate()
						.TakeWhile(_ => shape.transform.position.x < RightX)
						.ForEachAsync(_ =>
						{
							shape.transform.position += Vector3.right * Velocity * Time.deltaTime;
						}, cancellationToken: cancellationToken);
				}
				finally
				{
					shape.transform.position = new Vector3(RightX, shape.transform.position.y, shape.transform.position.z);
				}
			}
			else
			{
				throw new ArgumentException($"Shape '{shape}' does not exist.");
			}
		}
	}
}