using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

namespace Streamingle.Gaze
{
    [TrackColor(0.23f, 0.74f, 0.92f)]
    [TrackBindingType(typeof(BlendshapeGazeDriver))]
    [TrackClipType(typeof(BlendshapeGazeClip))]
    public sealed class BlendshapeGazeTrack : TrackAsset
    {
        public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
        {
            return ScriptPlayable<BlendshapeGazeMixerBehaviour>.Create(graph, inputCount);
        }

#if UNITY_EDITOR
        public override void GatherProperties(PlayableDirector director, IPropertyCollector collector)
        {
            var gazeDriver = director != null
                ? director.GetGenericBinding(this) as BlendshapeGazeDriver
                : null;

            var targetRenderer = gazeDriver != null ? gazeDriver.TargetRenderer : null;
            var profile = gazeDriver != null ? gazeDriver.Profile : null;
            var channels = profile != null ? profile.Channels : null;
            var mesh = targetRenderer != null ? targetRenderer.sharedMesh : null;
            if (targetRenderer != null && mesh != null && channels != null)
            {
                var channelNames = new HashSet<string>();
                var previewBindings = new AnimationClip
                {
                    name = "Blendshape Gaze Preview Bindings",
                    hideFlags = HideFlags.HideAndDontSave
                };

                try
                {
                    for (var i = 0; i < channels.Count; i++)
                    {
                        var channel = channels[i];
                        if (object.ReferenceEquals(channel, null))
                            continue;

                        var blendShapeIndex = profile.FindBlendShapeIndex(mesh, i);
                        if (blendShapeIndex < 0)
                            continue;

                        // AddFromName expects a SerializedProperty path, while
                        // blendShape.* is a synthetic Animator curve binding.
                        // Register it through a clip so Timeline's AnimationMode
                        // resolves and restores the real renderer property.
                        var channelName = mesh.GetBlendShapeName(blendShapeIndex);
                        if (string.IsNullOrWhiteSpace(channelName) || !channelNames.Add(channelName))
                            continue;

                        previewBindings.SetCurve(
                            string.Empty,
                            typeof(SkinnedMeshRenderer),
                            "blendShape." + channelName,
                            AnimationCurve.Constant(0f, 1f, 0f));
                    }

                    if (channelNames.Count > 0)
                        collector.AddFromClip(targetRenderer.gameObject, previewBindings);
                }
                finally
                {
                    Object.DestroyImmediate(previewBindings);
                }
            }

            base.GatherProperties(director, collector);
        }
#endif
    }
}
