using System;
using UnityEngine;

namespace FramedAnimator {
	[RequireComponent(typeof(SpriteRenderer))]
	public class Animator : MonoBehaviour {
		[SerializeField] private new Animation animation;
		public string CurrentAnimation => animation.name;

		private float _currentFrame;
		private int _renderingFrame;
		private int _limit;

		private SpriteRenderer _renderer;

		private bool _animationEnded;
		public event Action<string> OnAnimationEnd;

		private void Awake() {
			_renderer = GetComponent<SpriteRenderer>();
		}

		private void Update() {
			if (_renderingFrame >= _limit) {
				TryCallAnimationEnd();
				return;
			}
			UpdateAnimationFrame();
		}

		private void UpdateAnimationFrame() {
			_currentFrame += Time.deltaTime * animation.FrameRate;
			_renderingFrame = Mathf.Clamp(Mathf.FloorToInt(_currentFrame), 0, _limit);
			_renderer.sprite = animation.GetFrame(_renderingFrame);
		}

		private void TryCallAnimationEnd() {
			if (_renderingFrame < animation.FrameCount - 1 || _animationEnded) return;

			_currentFrame += Time.deltaTime * animation.FrameRate;
			_renderingFrame = Mathf.FloorToInt(_currentFrame);

			if (_renderingFrame <= _limit) return;
			_animationEnded = true;
			OnAnimationEnd?.Invoke(animation.name);
		}

		public void ChangeAnimation(Animation anim) {
			_animationEnded = false;
			_limit = _renderingFrame = 0;
			_currentFrame = 0f;
			animation = anim;

			_renderer.sprite = animation.GetFrame(_renderingFrame);
		}

		public void PlayUntil(float fraction) {
			_limit = Mathf.RoundToInt(animation.FrameCount * Mathf.Clamp01(fraction));
			_limit = Mathf.Clamp(_limit, 0, animation.FrameCount - 1);
		}
	}
}