using CommonAI.Zone;
using UnityEngine;
using System.Text.RegularExpressions;
using CommonLang;
using Sirenix.Utilities;
using ET.EventType;
using System.Collections.Generic;

namespace ET.Client
{
    
    [Event(SceneType.None)]
    public class PlayEffectEventHandler : BEvent<EventType.PlayEffectEvent>
    {
        private static Vector3 vecTemp = new();
        public override void OnEvent(PlayEffectEvent args)
        {
            vecTemp.Set(args.Pos.X, args.Pos.Y, args.Pos.Z);
            EffectMgr.Instance.PlayEffect(args.Effect, args.HostId, vecTemp, args.Time, args.Rotation).Coroutine();
        }
    }

    public class EffectMgr : Singleton<EffectMgr>, ISingletonUpdate
    {
        private HashMap<uint, EffectPlayInfo> playingList = new();
        
        private static Vector3 vecTemp = new();
        private List<uint> listTemp = new();

        public void Update()
        {
            listTemp.Clear();
            var now = Time.realtimeSinceStartup;
            foreach (var epi in playingList.Values)
            {
                if (epi.EndTime >= now)
                {
                    listTemp.Add(epi.Id);
                }
            }

            foreach(var id in listTemp)
            {
                RemoveEffect(id);
            }
        }

        public async ETTask<uint> PlayEffect(LaunchEffect effect, uint HostId, Vector3 pos, float time = 0f, float rotation = 0f)
        {
            var starttime = Time.realtimeSinceStartup;

            GameObject go = null;
            if (!effect.Name.IsNullOrWhitespace())
            {
                UnitRenderComponet render = null;
                if (effect.BindBody)
                {
                    render = ModelViewComponent.Instance.GetChild<UnitRenderComponet>(HostId);
                    if (render == null)
                    {
                        Log.Debug($"ignore unit effect: {effect.Name}@{HostId}, cause of No Render");
                        return 0;
                    }
                }

                go = await GameObjectPool.Instance.Acquire("Effect_" + effect.Name);
                var timeComponent = go.GetComponent<EffectTime>();
                if (time == 0f) time = timeComponent.duration;
                if (time < 0f) time = EffectPlayInfo.TIME_FOREVER;
                setupEffect(go, effect, render, pos, rotation);
            }

            if (effect.EarthQuakeMS > 0)
            {
                vecTemp.Set(effect.EarthQuakeXYZ, effect.EarthQuakeXYZ, effect.EarthQuakeXYZ);
                CameraMgr.ShakeMe(effect.EarthQuakeMS, vecTemp);
            }

            if (!effect.SoundName.IsNullOrWhitespace())
            {
                //TODO: Sound
            }

            var epi = ObjectPool.Instance.Fetch<EffectPlayInfo>();
            epi.Reset(go, starttime + time);
            playingList.Add(epi.Id, epi);
            return epi.Id;
        }

        private void setupEffect(GameObject go, LaunchEffect effectData, UnitRenderComponet render, Vector3 pos, float rotation)
        {
            var gt = go.transform;

            if (effectData.BindBody)
            {
                if (!effectData.BindPartName.IsNullOrWhitespace())
                {
                    gt.parent = render.GetBindPart(effectData.BindPartName);
                }
                else
                {
                    gt.parent = render.GameObject.transform;
                }
                vecTemp.Set(effectData.EffectOffsetX, 0, effectData.EffectOffsetY);
                gt.localPosition = vecTemp;
                if (effectData.Tag == "FixStartRotaion")
                {
                    gt.rotation = Quaternion.Euler(0, 90, 0);
                }
                else
                {
                    gt.localRotation = Quaternion.identity;
                }
            }
            else
            {
                gt.parent = GlobalViewComponent.Instance.Unit;
            }

            if (pos != Vector3.zero)
            {
                vecTemp.Set(effectData.EffectOffsetX, effectData.EffectHight, effectData.EffectOffsetY);
                gt.position = pos + vecTemp;
            }
            if (rotation != 0)
            {
                gt.rotation = RenderUtils.UnityRotationFromBattle(rotation);
            }
            var scale = effectData.ScaleToBodySize != 0 ? effectData.ScaleToBodySize : 1f;
            vecTemp.Set(scale, scale, scale);
            gt.localScale = vecTemp;

            if (!string.IsNullOrEmpty(effectData.Tag))
            {
                //Effect支持Tag设置Event,格式:Event:事件名(事件参数)
                Match m = Regex.Match(effectData.Tag, @"^Event:(\w+)\((.*)\)");
                if (m.Groups.Count >= 3)
                {
                    string eventName = m.Groups[1].Value;
                    string eventParam = m.Groups[2].Value;
                    if (!string.IsNullOrEmpty(eventName))
                    {
                        Log.Error("Not support: Effect({0}) Triggle event:{1}", effectData.Name, effectData.Tag);
                        /*EventManager.Fire("Event." + eventName, new Dictionary<string, object>()
                        {
                            {"param", eventParam},
                            {"position", gt.position}
                        });*/
                    }
                }
            }
            go.SetActive(true);
        }

        public void Clear()
        {
            foreach (var epi in playingList.Values)
            {
                GameObject.Destroy(epi.GameObj);
            }
            playingList.Clear();
        }

        public void RemoveEffect(uint id)
        {
            if (playingList.ContainsKey(id))
            {
                var info = playingList[id];
                playingList.Remove(id);
                GameObjectPool.Instance.RecycleObject(info.GameObj);
            }
        }
    }
}