using SerializableTypes;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using static KF3CharacterContainerSerializable;

namespace KF3.Containers
{
    [System.Serializable]
    public class CharacterKeyframeData : KeyframeData
    {
        public BoneList[] Bones = new BoneList[0];
        public MorphHelper[] Morphs = new MorphHelper[0];
        public MorphHelper[] Renderers = new MorphHelper[0];
        public bool
            EyesLocked,
            PhysicsEnabled,
            IKEnabled;
        public SVector3 LeftEyeRotation, RightEyeRotation;
        public SVector3 EyeTarget;
        public float LookAtStrength;
        public string CurrentAnimation;

        public CharacterKeyframeData() { }

        public CharacterKeyframeData(KF3CharacterContainer container)
        {
            this.Root = new SerializableTransform(container.transform);
            this.CurrentAnimation = container.CurrentAnimation;
            this.IKEnabled = container.IKEnabled;
            this.PhysicsEnabled = container.PhysicsEnabled;
            if (container as KF3CeruleanContainer != null)
            {
                var bones = new List<BoneList>
            {
                new BoneList()
                {
                    Name = "Body",
                    Bones = container.Body.boneList.Select(b => new SerializableBone(b)).ToArray()
                }
            };
                this.Bones = bones.ToArray();
                this.Renderers = container.Renderers.Select(r => new MorphHelper("", GetRendererName(container, r), 0, r.enabled)).ToArray();
            }
            else if (container as KF3FriendContainer != null)
            {
                var bones = new List<BoneList>
            {
                new BoneList()
                {
                    Name = "Body",
                    Bones = container.Body != null ? container.Body.boneList.Select(b => new SerializableBone(b)).ToArray() : new SerializableBone[0]
                }
            };
                var container1 = (KF3FriendContainer)container;
                bones.Add(new BoneList()
                {
                    Name = "Ears",
                    Bones = container1.Ears != null ? container1.Ears.boneList.Select(b => new SerializableBone(b)).ToArray() : new SerializableBone[0]
                });
                bones.Add(new BoneList()
                {
                    Name = "EarsAlt",
                    Bones = container1.EarsAlt != null ? container1.EarsAlt.boneList.Select(b => new SerializableBone(b)).ToArray() : new SerializableBone[0]
                });
                bones.Add(new BoneList()
                {
                    Name = "Tail",
                    Bones = container1.Tail != null ? container1.Tail.boneList.Select(b => new SerializableBone(b)).ToArray() : new SerializableBone[0]
                });
                bones.Add(new BoneList()
                {
                    Name = "TailAlt",
                    Bones = container1.TailAlt != null ? container1.TailAlt.boneList.Select(b => new SerializableBone(b)).ToArray() : new SerializableBone[0]
                });
                var extraBones = new List<SerializableBone>();
                foreach (var ik in container1.GetComponentsInChildren<InverseKinematics>())
                {
                    extraBones.Add(new SerializableBone(ik.target));
                    extraBones.Add(new SerializableBone(ik.elbow));
                }
                bones.Add(new BoneList()
                {
                    Name = "Extra",
                    Bones = extraBones.ToArray()
                });
                this.Bones = bones.ToArray();
                this.EyesLocked = container1.EyesLocked;
                this.LeftEyeRotation = container1.LeftEyeRotation.eulerAngles;
                this.RightEyeRotation = container1.RightEyeRotation.eulerAngles;
                this.EyeTarget = container1.EyeTarget.transform.localPosition;
                this.LookAtStrength = container1.LookAtStrength;

                var morphs = new List<MorphHelper>();
                foreach (var mesh in container1.Morphs)
                {
                    foreach (MorphHelper morph in mesh.Value)
                    {
                        morphs.Add(new MorphHelper(morph.ParentName, morph.Name, morph.Strength, morph.Value));
                    }
                }
                this.Morphs = morphs.ToArray();
                this.Renderers = container1.Renderers.Select(r => new MorphHelper("", GetRendererName(container1, r), 0, r.enabled)).ToArray();
            }
            else
            {
                Error.Log("Sum ting wong", UnityEngine.Color.red);
            }
        }

        public override KeyframeData Clone()
        {
            var keyframe = new CharacterKeyframeData();
            keyframe.Root = new SerializableTransform(this.Root);
            keyframe.Bones = this.Bones.Select(b => new BoneList() { Name = b.Name, Bones = b.Bones.Select(b1 => new SerializableBone(b1)).ToArray() }).ToArray();
            keyframe.EyesLocked = this.EyesLocked;
            keyframe.IKEnabled = this.IKEnabled;
            keyframe.PhysicsEnabled = this.PhysicsEnabled;
            keyframe.LeftEyeRotation = this.LeftEyeRotation;
            keyframe.RightEyeRotation = this.RightEyeRotation;
            keyframe.EyeTarget = this.EyeTarget;
            keyframe.LookAtStrength = this.LookAtStrength;
            keyframe.CurrentAnimation = this.CurrentAnimation;
            var morphs = new List<MorphHelper>();
            var renderers = new List<MorphHelper>();
            foreach (var morph in this.Morphs)
            {
                morphs.Add(new MorphHelper(morph.ParentName, morph.Name, morph.Strength, morph.Value));
            }
            foreach (var renderer in this.Renderers)
            {
                renderers.Add(new MorphHelper(renderer.ParentName, renderer.Name, renderer.Strength, renderer.Value));
            }
            keyframe.Morphs = morphs.ToArray();
            keyframe.Renderers = renderers.ToArray();
            return keyframe;
        }

        public override KeyframeData Lerp(KeyframeData target, float amount)
        {
            var target1 = target as CharacterKeyframeData;
            if (target1 == null) { Debug.LogError("Error, incompatible type"); return this; }

            var copy = this.Clone() as CharacterKeyframeData;
            copy.Root = copy.Root.LerpWith(target1.Root, amount);
            copy.EyeTarget = Vector3.Lerp(copy.EyeTarget, target1.EyeTarget, amount);
            foreach (var bonelist in copy.Bones)
            {
                for (int i = 0; i < bonelist.Bones.Length; i++)
                {
                    var bone1 = target1.Bones.FirstOrDefault(b => b.Name == bonelist.Name)?.Bones.FirstOrDefault(b => b.Name == bonelist.Bones[i].Name);
                    if (bone1 == null) continue;
                    bonelist.Bones[i].Transform = bonelist.Bones[i].Transform.LerpWith(bone1.Transform, amount);
                }
            }
            if (copy.Morphs != null && target1.Morphs != null)
            {
                foreach (var morph in copy.Morphs)
                {
                    var targetMorph = target1.Morphs.FirstOrDefault(m => m.ParentName == morph.ParentName && m.Name == morph.Name);
                    if (targetMorph == null) continue;
                    morph.Strength = Mathf.Lerp(morph.Strength, targetMorph.Strength, amount);
                }
            }
            return copy;
        }
    }
}