﻿using System;
using JLGames.RocketDriver.Actions.Animatorx;
using JLGames.RocketDriver.Actions.Utils;
using JLGames.RocketDriver.Actions.Wait;
using JLGames.RocketDriver.CSharp;
using UnityEngine;

namespace JLGames.RocketDriver.Games.PanelManager
{
    internal partial class PanelManager
    {
        public void ClosePanel(string panelId)
        {
            CloseLastPanel(panelId);
        }

        public void CloseFirstPanel(string panelId)
        {
            var instance = m_OpenList.GetByPanelId(panelId);
            CloseInstacnePanel(instance);
        }

        public void CloseLastPanel(string panelId)
        {
            var instance = m_OpenList.GetLastByPanelId(panelId);
            CloseInstacnePanel(instance);
        }

        public void CloseInstacnePanel(string instanceId)
        {
            var instance = FindInstace(instanceId);
            CloseInstacnePanel(instance);
        }

        public void CloseInstacnePanel(GameObject view)
        {
            var instance = FindInstace(view);
            CloseInstacnePanel(instance);
        }

        public void CloseInstacnePanel(IPanelInstance instance)
        {
            var value = instance as PanelInstance;
            if (null == value) return;
            CloseInstance(value);
        }

        public void ClosePanels()
        {
            for (var index = m_OpenList.Size - 1; index >= 0; index--)
            {
                CloseInstance(m_OpenList[index]);
            }
        }

        public void ClosePanels(string panelId)
        {
            ClosePanels(instance => instance.PanelId == panelId);
        }

        public void ClosePanels(Predicate<IPanelInstance> match)
        {
            for (var index = m_OpenList.Size - 1; index >= 0; index--)
            {
                var instance = m_OpenList[index];
                if (match.Invoke(instance))
                {
                    CloseInstance(instance);
                }
            }
        }

        private PanelInstance FindInstace(string instanceId)
        {
            var instance = m_OpenList.GetByInstanceId(instanceId);
            if (null != instance) return instance;
            instance = m_ClosingList.GetByInstanceId(instanceId);
            return instance;
        }

        private PanelInstance FindInstace(GameObject view)
        {
            var instance = m_OpenList.GetByView(view);
            if (null != instance) return instance;
            instance = m_ClosingList.GetByView(view);
            return instance;
        }

        private void CloseInstance(PanelInstance instance)
        {
            if (CheckInClosing(instance))
            {
                RemoveInstance(instance);
                return;
            }

            StartCloseInstance(instance);
            HandleCloseExtends(instance);
            RemoveFromLayer(instance);
        }

        private void StartCloseInstance(PanelInstance instance)
        {
            m_OpenList.RemoveInstance(instance);
            m_ClosingList.Add(instance);
            var info = instance.Info;
            DispatchEvent(PanelEvents.EventPanelRemove, info);
        }

        private void HandleCloseExtends(PanelInstance instance)
        {
            DisposeInstance(instance);
        }

        private void DisposeInstance(PanelInstance instance)
        {
            instance.CastMainScript<IDisposePanel>()?.DisposePanel(instance);
        }

        private void RemoveFromLayer(PanelInstance instance)
        {
            var animSettings = instance.Info.Settings.AnimSettings;
            if (null == animSettings || !animSettings.IncludeCloseAnim)
            {
                RemoveInstance(instance);
                FinishCloseInstacne(instance);
                return;
            }

            ShowCloseAnim(instance, animSettings);
        }

        private void ShowCloseAnim(PanelInstance instance, IPanelAnimSettings animSettings)
        {
            var c = m_Register.GetAnimator(animSettings.CloseKey);
            if (null == c)
            {
                Debug.LogWarning($"Close Anim[{animSettings.CloseKey}] is not found!");
                RemoveInstance(instance);
                return;
            }

            var view = instance.DisplayView;
            var anim = AnimatorUtils.TryAddAnimator(view);
            anim.runtimeAnimatorController = c;
            if (animSettings.IncludeCloseState)
            {
                anim.Play(animSettings.CloseState);
            }

            var info = anim.GetCurrentAnimatorClipInfo(0)[0];
            var len = info.clip.length;
            WaitBehaviourShared.Shared.InvokdSeconds(new Callback(OnAnimEnd, instance), len);
        }

        private void OnAnimEnd(params object[] args)
        {
            var instance = (PanelInstance) args[0];
            RemoveInstance(instance);
            FinishCloseInstacne(instance);
        }

        private void RemoveInstance(PanelInstance instance)
        {
            // 动画延时及用户多次操作带来的多次触发
            if (null == instance || instance.DisplayContainer == null) return;
            if (instance.DisplayContainer.transform.parent == null) return;
            TransformUtil.RemoveAndDestroy(instance.DisplayContainer.transform);
        }

        private void FinishCloseInstacne(PanelInstance instance)
        {
            var info = instance.Info;
            m_ClosingList.RemoveInstance(instance);
            DispatchEvent(PanelEvents.EventPanelRemoved, info);
            //DebugUtil.Log("剩余面板数量:", _openedList.Count);
            if (m_OpenList.Size == 0)
            {
                DispatchEvent(PanelEvents.EventPanelAllRemoved, null);
            }
        }

        private bool CheckInClosing(PanelInstance instance)
        {
            return m_ClosingList.ContainsInstance(instance);
        }
    }
}