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

namespace JLGames.RocketDriver.Games.PanelManager
{
    internal partial class PanelManager
    {
        public IPanelInstance ShowPanel(string panelId, string layerName = null)
        {
            return ShowPanel(panelId, (object) null, layerName);
        }

        public IPanelInstance ShowPanel(string panelId, object @params, string layerName = null)
        {
            if (string.IsNullOrEmpty(panelId)) return null;
            var info = m_Register.GetPanelInfo(panelId);
//            DebugUtil.Log("ShowPanel2:", info);
            return ShowPanel(info, @params, layerName);
        }

        public IPanelInstance ShowPanel(IPanelInfo info, string layerName = null)
        {
            return ShowPanel(info, (object) null, layerName);
        }

        public IPanelInstance ShowPanel(IPanelInfo info, object @params, string layerName = null)
        {
            if (null == info || CheckPanelLimit(info)) return null;
//            DebugUtil.Log("ShowPanel3:", info);
            var instance = new PanelInstance(info);
            StartShowInstance(instance);
            AddContainerToLayer(instance, layerName);
            m_Loader.LoadPanelAsset(info.AssetSettings, (view, succ) =>
            {
//                DebugUtil.Log("LoadPanelAsset:", succ, view);
                if (!succ) return;
                instance.SetDisplayView(view);
                instance.AppendViewToContainer();
                HandleShowExtends(instance, @params);
                SetOpenAnim(instance);
                FinishShowInstacne(instance);
            });
            return instance;
        }

        public IPanelInstance ShowPanel(string panelId, GameObject view, string layerName = null)
        {
            return ShowPanel(panelId, view, (object) null, layerName);
        }

        public IPanelInstance ShowPanel(string panelId, GameObject view, object @params, string layerName = null)
        {
            if (string.IsNullOrEmpty(panelId)) return null;
            var info = m_Register.GetPanelInfo(panelId);
//            DebugUtil.Log("ShowPanel4:", info);
            return ShowPanel(info, view, @params, layerName);
        }

        public IPanelInstance ShowPanel(IPanelInfo info, GameObject view, string layerName = null)
        {
            return ShowPanel(info, view, (object) null, layerName);
        }

        public IPanelInstance ShowPanel(IPanelInfo info, GameObject view, object @params,
            string layerName = null)
        {
            if (null == info || null == view || CheckPanelLimit(info)) return null;
            if (FindInstace(view) != null) return null;
//            DebugUtil.Log("ShowPanel5:", info);

            var instance = new PanelInstance(info);
            StartShowInstance(instance);
            AddContainerToLayer(instance, layerName);
            instance.SetDisplayView(view);
            instance.AppendViewToContainer();
            HandleShowExtends(instance, @params);
            SetOpenAnim(instance);
            FinishShowInstacne(instance);
            return instance;
        }

        //-----------------------------------------

        private bool CheckPanelLimit(IPanelInfo info)
        {
            if (info.MaxDisplayNum <= 0) return false;
            return m_OpenList.GetSize(info.Id) >= info.MaxDisplayNum;
        }

        private void StartShowInstance(PanelInstance instance)
        {
            m_OpenList.Add(instance);
            DispatchEvent(PanelEvents.EventPanelAdd, instance.Info);
        }

        private void AddContainerToLayer(PanelInstance instance, string layerName)
        {
            if (!m_ShowAfterFrame)
            {
                instance.InvokeBackgroundAction(false);
                AddContainerToLayer(instance.DisplayContainer.transform, layerName);
                return;
            }

            WaitBehaviourShared.Shared.InvokdEndOfFrame(() =>
            {
                instance.InvokeBackgroundAction(true);
                AddContainerToLayer(instance.DisplayContainer.transform, layerName);
            });
        }

        private void AddContainerToLayer(Transform container, string layerName)
        {
            var layer = m_Register.GetPanelLayer(layerName);
            if (null == container)
            {
                throw new Exception($"PanelLayer[{layerName}] is not exist.");
            }

            TransformUtil.AddChildTo(container, layer);
        }

        private void HandleShowExtends(PanelInstance instance, object @params)
        {
            InitInstance(instance);
            SetInstanceParams(instance, @params);
            RefreshInstance(instance);
        }

        private void InitInstance(PanelInstance instance)
        {
            instance.CastMainScript<IInitPanel>()?.InitPanel(instance);
        }

        private void SetInstanceParams(PanelInstance instance, object @params)
        {
            if (null != @params)
            {
                instance.CastMainScript<IParamsPanel>()?.SetPanelObjectParams(instance, @params);
                return;
            }

            if (instance.Info.AssetSettings.IncludeMainScriptParams)
            {
                instance.CastMainScript<IParamsPanel>()?.SetPanelStringParams(instance, instance.Info.AssetSettings.MainScriptParams);
            }
        }

        private void RefreshInstance(PanelInstance instance)
        {
            instance.CastMainScript<IRefreshPanel>()?.RefreshPanel(instance);
        }

        private void SetOpenAnim(PanelInstance instance)
        {
            var animSettings = instance.Info.Settings.AnimSettings;
            if (null == animSettings || !animSettings.IncludeOpenAnim) return;

            var c = m_Register.GetAnimator(animSettings.OpenKey);
            if (null == c)
            {
                Debug.LogWarning($"Open Anim[{animSettings.OpenKey}] is not found!");
                return;
            }

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

        private void FinishShowInstacne(PanelInstance instance)
        {
            DispatchEvent(PanelEvents.EventPanelAdded, instance.Info);
        }
    }
}