using UnityEngine;

namespace UNSLOW.EffectPractice.FirstTerm.MeshSlash
{
    [RequireComponent(typeof(MeshRenderer))]
    public class CrescentSlash : MonoBehaviour
    {
        [Header("再生設定")]
        [Tooltip("この GameObject が有効になった時に自動でアニメーションを開始します")]
        [SerializeField] private bool playOnEnable = true;

        [Tooltip("アニメーションの再生時間（秒） この時間内で各カーブを 0 から 1 の範囲で評価します")]
        [SerializeField, Min(0f)] private float lifeTime = 1f;

        [Tooltip("再生時間の終端に到達したら、アニメーションを最初から繰り返します")]
        [SerializeField] private bool loop;
        
        [Tooltip("ループする場合、次のループまでの待機時間（秒）")]
        [SerializeField] private float loopInterval = 1f;

        [Header("マテリアルプロパティ")]
        [Tooltip("シェーダー内部の Time に掛ける Speed 値")]
        [SerializeField] private float speed = 1f;

        [Tooltip("Phase の変化カーブ")]
        [SerializeField] private AnimationCurve phaseCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f);

        [Tooltip("Intensity の変化カーブ")]
        [SerializeField] private AnimationCurve intensityCurve = AnimationCurve.Linear(0f, 1f, 1f, 1f);

        private static readonly int SpeedPropertyId = Shader.PropertyToID("_Speed");
        private static readonly int PhasePropertyId = Shader.PropertyToID("_Phase");
        private static readonly int IntensityPropertyId = Shader.PropertyToID("_Intensity");

        private MeshRenderer _meshRenderer;
        private MaterialPropertyBlock _propertyBlock;
        private float _elapsedTime;
        private bool _playing;

        private void Awake()
        {
            _meshRenderer = GetComponent<MeshRenderer>();
            _propertyBlock = new MaterialPropertyBlock();
        }

        private void OnEnable()
        {
            if (playOnEnable)
                Play();
            else
                Apply(0f);
        }

        private void Update()
        {
            if (!_playing)
                return;

            _elapsedTime += Time.deltaTime;

            var normalizedTime = lifeTime <= 0f ? 1f : Mathf.Clamp01(_elapsedTime / lifeTime);

            Apply(normalizedTime);

            if (normalizedTime < 1f)
                return;

            if (loop && lifeTime > 0f)
            {
                _elapsedTime %= lifeTime;
                
                if (loopInterval > 0f)
                    _elapsedTime -= loopInterval;
                
                return;
            }

            _playing = false;
        }

#if UNITY_EDITOR
        private void OnValidate()
        {
            lifeTime = Mathf.Max(0f, lifeTime);
        }
#endif

        public void Play()
        {
            _elapsedTime = 0f;
            _playing = true;
            Apply(0f);
        }

        public void Stop()
        {
            _playing = false;
        }

        private void Apply(float normalizedTime)
        {
            _meshRenderer.GetPropertyBlock(_propertyBlock);
            _propertyBlock.SetFloat(SpeedPropertyId, speed);
            _propertyBlock.SetFloat(PhasePropertyId, phaseCurve.Evaluate(normalizedTime));
            _propertyBlock.SetFloat(IntensityPropertyId, intensityCurve.Evaluate(normalizedTime));
            _meshRenderer.SetPropertyBlock(_propertyBlock);
        }
    }
}
