using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;

public class GrabDeformation : BaseDeformation {
    public override string DeformationName { get; protected set; } = "Grab deform";

    public override string Description { get; set; } = "Grab deform";
    private float _intensity = 1;
    public override float Intensity
    {
        get
        {
            return _intensity;
        }

        set
        {
            _intensity = Mathf.Clamp(value, minIntensity, maxIntensity);
        }
    }

    public bool computeOnCpu = false;


    private void Update()
    {
        if (IsDeforming)
        {
            if (computeOnCpu)
            {
                GrabDeformationOnCPU();
            } else
            {
                computeShaderManager.GrabDeformation(DeformationManager.LocalLastPosition, DeformationManager.LocalCurrentPosition, DeformationManager.ScaledAreaOfEffect, Intensity,
                    DeformationManager.MaskedVertices, DeformationManager.CurrentVertices, DeformationManager.DeformingMesh);
            }
        }
        
    }

    [SerializeField]
    private ComputeShaderManager computeShaderManager;

    public override void InitializeDeformation(DeformationManager deformationManager)
    {
        DeformationManager = deformationManager;
        if (computeShaderManager.VerticesCount != deformationManager.CurrentVertexColors.Length)
        {
            computeShaderManager.SetupBuffers(deformationManager.CurrentVertexColors.Length);
        }
    }

    public override void StartDeforming()
    {
        if (IsDeforming)
        {
            return;
        }
        computeShaderManager.StartGrabDeformation(DeformationManager.MaskedVertices, DeformationManager.CurrentVertices);
        IsDeforming = true;
    }

    public override void StopDeforming()
    {
        IsDeforming = false;
        DeformationManager.DeformingMesh.RecalculateNormals();
        DeformationManager.DeformingMesh.RecalculateBounds();
    }

    public void GrabDeformationOnCPU()
    {
#if DEBUG
        System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
        stopWatch.Start();
#endif

        float deformationIntensity  = Intensity / 10000f;
        Vector3 lastPosition = DeformationManager.LocalLastPosition;
        Vector3 newPosition = DeformationManager.LocalCurrentPosition;
        Vector3 direction = newPosition - lastPosition;
        float areaOfEffect = DeformationManager.ScaledAreaOfEffect;

        Parallel.For(0, DeformationManager.CurrentVertices.Length, i =>
        {
            if (DeformationManager.MaskedVertices[i] == 1)
            {
                return;
            }

            float distance = Vector3.Distance(DeformationManager.CurrentVertices[i], lastPosition);

            if (distance <= areaOfEffect)
            {
                float deformationAttenuation = deformationIntensity / (deformationIntensity + distance * distance);


                Vector3 deformationOffset = deformationAttenuation * (direction);
                DeformationManager.CurrentVertices[i] += deformationOffset;

            }
        });
        
        DeformationManager.DeformingMesh.vertices = DeformationManager.CurrentVertices;

#if DEBUG
        stopWatch.Stop();
        if (PerformanceTest.Instance != null)
            PerformanceTest.Instance.LogDeformationTime(stopWatch.Elapsed.Milliseconds);
#endif
    }


}
