using KF3.Containers;
using System.Collections;
using System.Linq;
using UnityEngine;

public class KF3CharacterContainer : KF3ObjectContainer
{
    protected override System.Type _serializeType => typeof(KF3CharacterContainerSerializable);
    protected override System.Type _keyframeType => typeof(CharacterKeyframeData);


    public bool
        BonesVisible = true,
        PhysicsEnabled = true,
        IKEnabled = true;
    public string
        CostumeName,
        AnimationName;
    public CharaModelReferencer
        Body,
        BodyAnimation;
    public SimpleAnimation
        BodySimpleAnimation;

    public float AnimationSpeed = 0;
    public string CurrentAnimation = "";

    protected IEnumerator BuildGeneral(string modelName, string animSetName)
    {
        enabled = false;
        string mIdLong = modelName.Split('_', '.')[1];
        string mCostume = modelName.Split('_', '.')[2];
        string aIdLong = animSetName.Split('_', '.')[1];

        if (LoadInProgress) yield break;
        LoadInProgress = true;
        ModelId = int.Parse(mIdLong);
        CostumeName = modelName;
        AnimationName = animSetName;

        using(new KeyframeToggleContext(this))
        {
            yield return GetModel(mIdLong, mCostume);
            yield return GetAnimations(aIdLong);
            SetAnimationReferences();
            SetBones();
            DoStuff();
        }
        SetKeyframe();
        enabled = true;
    }

    public virtual void SetAnimationReferences() {}

    public virtual void SetBones() {}

    public virtual void DoStuff() {}

    public virtual void ToggleBonesVisible(bool value)
    {
        BonesVisible = value;
        foreach (var handle in Handles.Where(h => h as UIHandleBone != null))
        {
            handle.ToggleActive(value);
        }
    }

    public void TogglePhysics()
    {
        TogglePhysics(!PhysicsEnabled);
    }

    public void TogglePhysics(bool value = true)
    {
        PhysicsEnabled = value;
        foreach (var handle in Handles.Where(h => h.GetType() == typeof(UIHandlePhysicsBone)))
        {
            handle.Target.GetComponent<Osage>().enabled = value;
        }
    }

    public void ResetBones()
    {
        foreach (var bone in Handles)
        {
            bone.TransformResetAll();
        }
    }

    public string GetAnimationName()
    {
        if (BodySimpleAnimation.clip != null)
        {
            return BodySimpleAnimation.GetStates().FirstOrDefault(st => st.clip.name == BodySimpleAnimation.clip.name).name;
        }
        else return "";
    }

    public void PlayBodyAnimation(string clipName)
    {
        PlayAnimation(BodySimpleAnimation, clipName);
    }

    public void PlayAnimation(SimpleAnimation anim, string clipName, float time = -1)
    {
        if (anim == null) return;
        else if (string.IsNullOrEmpty(clipName))
        {
            anim.Stop();
            anim.clip = null;
            anim.enabled = false;
            return;
        }
        anim.enabled = true;
        anim.clip = anim.GetState(clipName).clip;
        anim.Play(anim.GetStates().FirstOrDefault(state => state.clip == anim.clip).name);
        anim.GetStates().FirstOrDefault(state => state.clip == anim.clip).speed = AnimationSpeed;
        if(time != -1)
        {
            anim.GetStates().FirstOrDefault(state => state.clip == anim.clip).time = time;
        }
    }

    public void RewindAllAnimations()
    {
        if (BodySimpleAnimation && BodySimpleAnimation.clip != null)
        {
            BodySimpleAnimation.Rewind();
        }
        if (this as KF3FriendContainer != null)
        {
            var EarsSimpleAnimation = ((KF3FriendContainer)this).EarsSimpleAnimation;
            var TailSimpleAnimation = ((KF3FriendContainer)this).EarsSimpleAnimation;
            if (EarsSimpleAnimation && EarsSimpleAnimation.clip != null)
            {
                EarsSimpleAnimation.Rewind();
            }
            if (TailSimpleAnimation && TailSimpleAnimation.clip != null)
            {
                TailSimpleAnimation.Rewind();
            }
        }
    }

    public void UnwindAllAnimations()
    {
        if (BodySimpleAnimation && BodySimpleAnimation.clip != null)
        {
            BodySimpleAnimation.Unwind();
        }
        if (this as KF3FriendContainer != null)
        {
            var EarsSimpleAnimation = ((KF3FriendContainer)this).EarsSimpleAnimation;
            var TailSimpleAnimation = ((KF3FriendContainer)this).EarsSimpleAnimation;
            if (EarsSimpleAnimation && EarsSimpleAnimation.clip != null)
            {
                EarsSimpleAnimation.Unwind();
            }
            if (TailSimpleAnimation && TailSimpleAnimation.clip != null)
            {
                TailSimpleAnimation.Unwind();
            }
        }
    }

    public void SetAnimationTimeScale(float timeScale)
    {
        if (BodySimpleAnimation && BodySimpleAnimation.clip != null)
        {
            SimpleAnimation.State currentClip = BodySimpleAnimation.GetStates().FirstOrDefault(state => state.clip == BodySimpleAnimation.clip);
            currentClip.speed = timeScale;
        }
        if (this as KF3FriendContainer != null)
        {
            var EarsSimpleAnimation = ((KF3FriendContainer)this).EarsSimpleAnimation;
            var TailSimpleAnimation = ((KF3FriendContainer)this).EarsSimpleAnimation;
            if (EarsSimpleAnimation && EarsSimpleAnimation.clip != null)
            {
                SimpleAnimation.State currentClip = EarsSimpleAnimation.GetStates().FirstOrDefault(state => state.clip == EarsSimpleAnimation.clip);
                currentClip.speed = timeScale;
            }
            if (TailSimpleAnimation && TailSimpleAnimation.clip != null)
            {
                SimpleAnimation.State currentClip = TailSimpleAnimation.GetStates().FirstOrDefault(state => state.clip == TailSimpleAnimation.clip);
                currentClip.speed = timeScale;
            }
        }
    }

    public void ChangeAnimationTimeScale(int time)
    {
        if (BodySimpleAnimation && BodySimpleAnimation.clip != null)
        {
            SimpleAnimation.State currentClip = BodySimpleAnimation.GetStates().FirstOrDefault(state => state.clip == BodySimpleAnimation.clip);
            currentClip.speed += 0.2f * time;
        }
        if (this as KF3FriendContainer != null)
        {
            var EarsSimpleAnimation = ((KF3FriendContainer)this).EarsSimpleAnimation;
            var TailSimpleAnimation = ((KF3FriendContainer)this).EarsSimpleAnimation;
            if (EarsSimpleAnimation && EarsSimpleAnimation.clip != null)
            {
                SimpleAnimation.State currentClip = EarsSimpleAnimation.GetStates().FirstOrDefault(state => state.clip == EarsSimpleAnimation.clip);
                currentClip.speed += 0.2f * time;
            }
            if (TailSimpleAnimation && TailSimpleAnimation.clip != null)
            {
                SimpleAnimation.State currentClip = TailSimpleAnimation.GetStates().FirstOrDefault(state => state.clip == TailSimpleAnimation.clip);
                currentClip.speed += 0.2f * time;
            }
        }
    }

    public void ResetAnimationTimeScale()
    {
        if (BodySimpleAnimation && BodySimpleAnimation.clip != null)
        {
            SimpleAnimation.State currentClip = BodySimpleAnimation.GetStates().FirstOrDefault(state => state.clip == BodySimpleAnimation.clip);
            currentClip.speed = currentClip.speed == 0 ? 1 : 0;
        }
        if (this as KF3FriendContainer != null)
        {
            var EarsSimpleAnimation = ((KF3FriendContainer)this).EarsSimpleAnimation;
            var TailSimpleAnimation = ((KF3FriendContainer)this).EarsSimpleAnimation;
            if (EarsSimpleAnimation && EarsSimpleAnimation.clip != null)
            {
                SimpleAnimation.State currentClip = EarsSimpleAnimation.GetStates().FirstOrDefault(state => state.clip == EarsSimpleAnimation.clip);
                currentClip.speed = currentClip.speed == 0 ? 1 : 0;
            }
            if (TailSimpleAnimation && TailSimpleAnimation.clip != null)
            {
                SimpleAnimation.State currentClip = TailSimpleAnimation.GetStates().FirstOrDefault(state => state.clip == TailSimpleAnimation.clip);
                currentClip.speed = currentClip.speed == 0 ? 1 : 0;
            }
        }
    }

    public override void SetKeyframe(int frameNum = -1)
    {
        base.SetKeyframe(frameNum);
    }

    protected CharaModelReferencer spawnAndGetReferencer(AssetBundle ab)
    {
        if (ab != null)
        {
            GameObject go = Instantiate(ab.LoadAsset(ab.GetAllAssetNames()[0]) as GameObject, transform);
            ab.Unload(false);
            return go.GetComponent<CharaModelReferencer>();
        }
        return null;
    }

    /// <summary> Find and load all files related to selected model </summary>
    public virtual IEnumerator GetModel(string bodyIdLong, string costumeId)
    {
        yield break;
    }

    /// <summary> Find and load all files related to selected animation set </summary>
    public virtual IEnumerator GetAnimations(string idLong)
    {
        yield break;
    }
}
