﻿using UnityEngine;
using UnityEngine.VFX;
using UnityEngine.VFX.Utility;

namespace ImpactCFX.VFXBatch
{
    [AddComponentMenu("Impact CFX/VFX Batch/Impact VFX Batch Master")]
    public class ImpactVFXBatchMaster : MonoBehaviour
    {
        [SerializeField]
        [Tooltip("The Visual Effect that is being controlled.")]
        private VisualEffect visualEffect;
        [SerializeField]
        [Tooltip("The vectors texture property on the visual effect.")]
        private string vectorsProperty;
        [SerializeField]
        [Tooltip("The count integer property on the visual effect.")]
        private string countProperty;
        [SerializeField]
        [Tooltip("The capacity integer property on the visual effect.")]
        private string capacityProperty;
        [SerializeField]
        [Tooltip("The maximum number of effects that can be processed in a single frame.")]
        private int capacity = 32;

        private Texture2D inputTexture;
        private int inputCount;
        private Color[] colors;
        private bool needsTextureUpdate;

        private int effectID;

        private ExposedProperty transformExposedProperty;
        private ExposedProperty countExposedProperty;

        public int Capacity => capacity;

        private ParticleEffectType particleEffectType;

        private void Awake()
        {
            inputTexture = new Texture2D(capacity, 3, TextureFormat.RGBAFloat, 0, true);
            inputTexture.wrapMode = TextureWrapMode.Clamp;
            inputTexture.filterMode = FilterMode.Point;

            colors = new Color[capacity * 3];

            transformExposedProperty = vectorsProperty;
            countExposedProperty = countProperty;

            visualEffect.SetInt(capacityProperty, capacity);
        }

        private void Reset()
        {
            visualEffect = GetComponentInChildren<VisualEffect>();
        }

        public void SetEffectType(ParticleEffectType particleEffectType)
        {
            this.particleEffectType = particleEffectType;

            //Begin playing looped effects immediately
            if (particleEffectType == ParticleEffectType.Looped)
                visualEffect.Play();
        }

        public void SetInput(CollisionResultData collisionResultData)
        {
            if (inputCount >= capacity)
                return;

            int pointIndex = inputCount;
            int normalIndex = inputCount + capacity;
            int velocityIndex = inputCount + capacity * 2;

            colors[pointIndex] = new Color(collisionResultData.Point.x, collisionResultData.Point.y, collisionResultData.Point.z, collisionResultData.MaterialComposition);
            colors[normalIndex] = new Color(collisionResultData.Normal.x, collisionResultData.Normal.y, collisionResultData.Normal.z);
            colors[velocityIndex] = new Color(collisionResultData.Velocity.x, collisionResultData.Velocity.y, collisionResultData.Velocity.z);

            needsTextureUpdate = true;
            inputCount++;
        }

        public void ApplyVisualEffectParameters()
        {
            visualEffect.SetInt(countExposedProperty, inputCount);

            if (needsTextureUpdate)
            {
                inputTexture.SetPixels(colors);
                inputTexture.Apply();

                visualEffect.SetTexture(transformExposedProperty, inputTexture);

                //Play one shot effects every update to trigger spawning
                if (particleEffectType == ParticleEffectType.OneShot)
                    visualEffect.Play();
            }

            ResetEffect();
        }

        public void SetEffectID(int effectID)
        {
            this.effectID = effectID;
        }

        public int GetEffectID()
        {
            return effectID;
        }

        public void ResetEffect()
        {
            inputCount = 0;
            needsTextureUpdate = false;
        }
    }
}