using System;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;
using UnityEngine.Splines;

namespace Unity.Splines.Examples
{
    [CustomEditor(typeof(DisplayCurvatureOnSpline))]
    public class DisplayCurvatureOnSplineEditor : UnityEditor.Editor
    {
        void OnSceneGUI()
        {
            var displayScript = ( (DisplayCurvatureOnSpline)target );
            var curvatureTimes = displayScript.m_CurvatureTimes;
            var container = displayScript.container;
            
            if(container.Spline == null || Event.current.type != EventType.Repaint)
                return;

            using var nativeSpline = new NativeSpline(container.Spline, container.transform.localToWorldMatrix);

            foreach(var config in curvatureTimes)
            {
                if(!config.display)
                    continue;
                
                var t = math.clamp(config.time, 0f, 1f);
                
                if(container.transform.lossyScale != Vector3.one)
                {
                    //Convert t to be the same for the spline and the spline data in case
                    //a scale is applied on the SplineContainer GameObject
                    var curveIndex = container.Spline.SplineToCurveT(t, out float curveT);
                    t = nativeSpline.CurveToSplineT(curveIndex + curveT);
                }

                //Compute Spline Position in World Space
                var nativeSplinePos = nativeSpline.EvaluatePosition(t);

                //Compute Curvature at t, Curvature k = 1/radius
                var curvature = nativeSpline.EvaluateCurvature(t);
                
                //Compute the curvature center = i.e the center point of the tangent circle at the spline at t
                var curvatureCenter = nativeSpline.EvaluateCurvatureCenter(t);
                
                //Computing signed curvature :
                //Evaluate on which side of the spline is the curvature bending
                var up = nativeSpline.EvaluateUpVector(t);
                var velocity = nativeSpline.EvaluateTangent(t);
                var acceleration = nativeSpline.EvaluateAcceleration(t);
                var curvatureUp = math.normalize(math.cross(acceleration, velocity));
                
                var c = curvature * math.sign(math.dot(up, curvatureUp));
                c = math.clamp(5f* c, -1f, 1f);
                var curvatureColor = new Color(
                    c < 0 ? c + 1 : 1,
                    math.abs(c),
                    c < 0 ? 1 : 1 - c);

                using(new Handles.DrawingScope(curvatureColor))
                    Handles.DrawSolidDisc(curvatureCenter, curvatureUp, math.length(curvatureCenter - nativeSplinePos));

                using(new Handles.DrawingScope(Color.black))
                    Handles.SphereHandleCap(-1, nativeSplinePos, Quaternion.identity, 0.15f * HandleUtility.GetHandleSize(nativeSplinePos), EventType.Repaint);

            }
        }
    }
}