using CommonAI.Zone;
using CommonAI.Zone.ZoneEditor;
using CommonAI.ZoneClient;
using CommonLang;
using CommonLang.Vector;
using pomelo.area;
using pomelo.connector;
using Pomelo.DotNetClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XmdsCommon.Message;
using XmdsCommon.ZoneClient;
using XmdsCommon.EditorData;

namespace XmdsBattleClientBot.Bot
{
    // 游戏服相关 //
    partial class BotClient
    {
        public EnterSceneResponse LastEnterSceneResponse { get; private set; }
        public ChangeAreaResponse LastChangeAreaResponse { get; private set; }
        public RegionManager CurrentRegionManager { get; private set; }
        public NpcManager CurrentNpcManager { get; private set; }
        public HZZoneLayer CurrentZoneLayer { get; private set; }
        public ZoneActor CurrentZoneActor { get; private set; }
        public CommonAI.Data.SceneType CurrentSceneType { get; private set; }

        public void SendUnitGuard(bool guard)
        {
            if(CurrentZoneActor != null)
            {
                CurrentZoneActor.SendUnitGuard(guard);
            }            
        }

        private void callback_gs_ChangeAreaPush(ChangeAreaPush push)
        {
            CurrentSceneType = (CommonAI.Data.SceneType)push.s2c_sceneType;
            this.IsFree = (CurrentSceneType == CommonAI.Data.SceneType.Normal || CurrentSceneType == CommonAI.Data.SceneType.HUANJING);
        }

        public void gs_EnterScene(Action<EnterSceneResponse> action, Action<Exception> error = null)
        {
            lock (this)
            {
                //TODO
                this.Client.LoginHandler.Request_EnterScene("" ,(r) =>
                {
                    this.LastEnterSceneResponse = r; action(r);
                }, (err) => { if (error != null) error(err); });
            }
        }

        /// <summary>
        /// </summary>
        /// <param name="name"></param>
        /// <param name="type">0:普通进入,1:收到弹框点确认进副本</param>
        /// <param name="action"></param>
        /// <param name="error"></param>
        public void gs_ChangeSceneByTransport(string name, int type, Action<ChangeAreaResponse> action, Action<Exception> error = null)
        {
            client.GameSocket.playerHandler.changeAreaRequest(name, type, (err, msg) =>
            {
                if (type == 0)
                {
                    client.GameSocket.playerHandler.changeAreaRequest(name, 1, (ex1, msg1) =>
                    {
                        this.LastChangeAreaResponse = msg1;
                        if (msg1 != null && action != null) { action(msg1); }
                        if (ex1 != null && error != null) { error(ex1); }
                    });
                }
                else
                {
                    this.LastChangeAreaResponse = msg;
                    if (msg != null && action != null) { action(msg); }
                    if (err != null)
                    {
                        if (error != null)
                        {
                            error(err);
                        } else
                        {
                            log.Log(err.Message);
                        }
                    }
                }
            });
        }

        //监听战斗层已创建
        private void callback_client_OnCreateBattleClient(XmdsBattleClient.Battle.XmdsBattleClient obj)
        {
            if (CurrentNpcManager != null)
            {
                CurrentNpcManager.Dispose();
            }
            CurrentNpcManager = new NpcManager(this);
            obj.Layer.LayerInit += callback_layer_OnInit;
            obj.Layer.ActorAdded += callback_layer_OnActorAdded;
            obj.Layer.DecorationChanged += callback_layer_OnDecorationChanged;
            obj.Layer.MessageReceived += callback_layer_MessageReceived;
            obj.Layer.OnScriptCommand += callback_layer_OnScriptCommand; ;
        }

        private void callback_layer_OnInit(CommonAI.ZoneClient.ZoneLayer layer)
        {
            CurrentZoneLayer = layer as HZZoneLayer;
            CurrentZoneActor = null;
            if (CurrentRegionManager != null)
                CurrentRegionManager.Dispose();
            CurrentRegionManager = new RegionManager(this);
            Client.GameSocket.resourceHandler.queryAreaDataRequest((ex, msg) =>
            {
                if (ex == null)
                {
                    CurrentNpcManager.AddAreaNpcList(msg);
                }
            });
        }
        private void callback_layer_OnActorAdded(CommonAI.ZoneClient.ZoneLayer layer, CommonAI.ZoneClient.ZoneActor actor)
        {
            CurrentZoneActor = layer.Actor;
            if (CurrentRegionManager != null)
            {
                CurrentRegionManager.callback_layer_OnActorAdded(actor);
            }
        }
        private void callback_layer_OnDecorationChanged(CommonAI.ZoneClient.ZoneLayer layer, CommonAI.ZoneClient.ZoneEditorDecoration ed)
        {

        }
        private void callback_layer_MessageReceived(ZoneLayer layer, CommonLang.Protocol.IMessage e)
        {
            if (e is ScriptCommandEvent)
            {
                //                 ScriptCommandEvent evt = e as ScriptCommandEvent;
                //                 string[] evt_param = evt.message.Split('|');
                //                 if (evt_param.Length == 2)
                //                 {
                //                     object[] param = evt_param[1].Split(',');
                //                     string funcName = "GlobalHooks." + evt_param[0];
                //                     if (LuaScriptMgr.Instance.IsFuncExists(funcName))
                //                     {
                //                         LuaScriptMgr.Instance.CallLuaFunction(funcName, param);
                //                     }
                //                 }
            }
            else if (e is ScriptAddUnitEventsB2C)
            {
                CurrentNpcManager.AddNpc(e as ScriptAddUnitEventsB2C);
            }
            else if (e is ScriptRemoveUnitEventsB2C)
            {
                CurrentNpcManager.RemoveNpc(e as ScriptRemoveUnitEventsB2C);
            }
        }
        private void callback_layer_OnScriptCommand(ZoneLayer layer, string msg)
        {
            string[] cmds = msg.Split(new char[] { '|' });
            if (cmds[0] == "ScriptAddUnitEvent")
            {
                CurrentNpcManager.AddNPC(cmds);
            }
            else if (cmds[0] == "ScriptRemoveUnitEvent")
            {

            }
        }

        public class NpcManager : IDisposable
        {
            private readonly BotClient bot;
            private HashMap<uint, Npc> AreaNpcList = new HashMap<uint, Npc>();
            private HashMap<uint, ScriptAddUnitEventsB2C> ZoneNpcList = new HashMap<uint, ScriptAddUnitEventsB2C>();
            internal NpcManager(BotClient bot)
            {
                this.bot = bot;
            }

            public void Dispose()
            {
                AreaNpcList.Clear();
                ZoneNpcList.Clear();
            }
            internal void AddAreaNpcList(pomelo.area.QueryAreaDataResponse msg)
            {
                AreaNpcList.Clear();
                if (msg.s2c_npcs != null)
                {
                    foreach (var npc in msg.s2c_npcs)
                    {
                        AreaNpcList.Add(npc.id, npc);
                    }
                }
            }
            internal void AddNPC(string[] param)
            {
                int templateId = 0;
                int.TryParse(param[1], out templateId);
                //int x = 0;
                //int.TryParse(param[2], out x);
                //int y = 0;
                //int.TryParse(param[3], out y);
                //                 npcs[fake_id_count] = templateId;
                //                 --fake_id_count;
            }
            internal void AddNpc(ScriptAddUnitEventsB2C e)
            {
                ZoneNpcList.Put(e.ObjectID, e);
            }
            internal void RemoveNpc(ScriptRemoveUnitEventsB2C e)
            {
                ZoneNpcList.RemoveByKey(e.ObjectID);
            }
            /// <summary>
            /// 根据模板找单位
            /// </summary>
            /// <param name="templateID"></param>
            /// <returns></returns>
            public Vector2 GetNpcByTemplateID(int templateID)
            {
                foreach (var u in ZoneNpcList.Values)
                {
                    if (u.TemplateID == templateID)
                    {
                        return new Vector2(u.X, u.Y);
                    }
                }
                if (bot.CurrentZoneLayer != null)
                {
                    foreach (var u in AreaNpcList.Values)
                    {
                        if (u.templateId == templateID)
                        {

                            var vu = bot.CurrentZoneLayer.GetUnit(u.id);
                            if (vu != null)
                            {
                                return new Vector2(vu.X, vu.Y);
                            }

                        }
                    }
                    var tu = bot.CurrentZoneLayer.GetUnitByTemplateID(templateID);
                    if (tu != null)
                    {
                        return new Vector2(tu.X, tu.Y);
                    }
                    var fu = bot.CurrentZoneLayer.GetUnitFlagByTemplateID(templateID);
                    if (fu != null)
                    {
                        return new Vector2(fu.X, fu.Y);
                    }
                }
                return null;
            }
        }


        public class RegionManager : IDisposable
        {
            private readonly BotClient bot;
            /// <summary>
            /// 客户端本地维护的Region集合
            /// </summary>
            private List<RegionData> mRegions = null;
            private List<SceneTransRegion> mSceneTransRegionList = null;

            internal RegionManager(BotClient bot)
            {
                this.bot = bot;
                this.mRegions = new List<RegionData>(bot.Client.BattleClient.Layer.Data.Regions);
                this.mSceneTransRegionList = new List<SceneTransRegion>();
                foreach (var flag in bot.Client.BattleClient.Layer.Flags)
                {
                    var ab = flag.EditorData.GetAbilityOf<XmdsCommon.EditorData.XmdsSceneTransportAbilityData>();
                    if (ab != null)
                    {
                        mSceneTransRegionList.Add(new SceneTransRegion(bot, flag, ab));
                    }
                }
            }

            public void Dispose()
            {
                mRegions.Clear();
                mSceneTransRegionList.Clear();
            }

            public List<RegionData> AllRegions()
            {
                return new List<RegionData>(mRegions);
            }
            public List<SceneObjectData> AllTransports()
            {
                List<SceneObjectData> ret = new List<SceneObjectData>();
                for (int i = 0; i < mSceneTransRegionList.Count; i++)
                {
                    ret.Add(mSceneTransRegionList[i].Data.EditorData);
                }
                return ret;
            }
            public bool CheckTrans(int type, bool force_trans, Action<Exception> error = null)
            {
                for (int i = 0; i < mSceneTransRegionList.Count; i++)
                {
                    if (mSceneTransRegionList[i].CheckTrans(type, force_trans, error))
                    {
                        return true;
                    }
                }
                return false;
            }

            internal void Update()
            {
                for (int i = 0; i < mSceneTransRegionList.Count; i++)
                {
                    mSceneTransRegionList[i].Update();
                }
            }

            /// <summary>
            /// 监听主角进入
            /// </summary>
            /// <param name="actor"></param>
            internal void callback_layer_OnActorAdded(CommonAI.ZoneClient.ZoneActor actor)
            {
                for (int i = 0; i < mSceneTransRegionList.Count; i++)
                {
                    mSceneTransRegionList[i].BindActor(actor);
                }
            }


            private class SceneTransRegion
            {
                private readonly BotClient bot;

                private AbilityData m_Ability = null;
                private ZoneFlag m_Data = null;
                private CommonAI.ZoneClient.ZoneActor mActor = null;
                private float mRadius = 0;
                private bool mSendMsg = true;

                public AbilityData Ability { get { return m_Ability; } }
                public ZoneFlag Data { get { return m_Data; } }

                internal SceneTransRegion(BotClient bot, ZoneFlag rd, AbilityData data)
                {
                    this.bot = bot;
                    this.m_Ability = data;
                    this.m_Data = rd;
                    this.mRadius = m_Data.EditorData.Radius;
                }

                internal void BindActor(CommonAI.ZoneClient.ZoneActor actor)
                {
                    this.mActor = actor;
                }

                internal void Update()
                {
                    if (mActor != null)
                    {
                        if (CMath.intersectRound(m_Data.X, m_Data.Y, mRadius, mActor.X, mActor.Y, mActor.BodySize))
                        {
                            if (mSendMsg == false)
                            {
                                mSendMsg = true;
                                SendTransRequest(1, false);
                            }
                        }
                        else
                        {
                            mSendMsg = false;
                        }
                    }
                }

                internal bool CheckTrans(int type, bool force_trans, Action<Exception> error = null)
                {
                    if (mActor != null)
                    {
                        if (CMath.intersectRound(m_Data.X, m_Data.Y, mRadius, mActor.X, mActor.Y, mActor.BodySize))
                        {
                            return SendTransRequest(type, force_trans, error);
                        }
                    }
                    return false;
                }

                //发送协议.
                private bool SendTransRequest(int type, bool force_trans, Action<Exception> error = null)
                {
                    if (m_Data.Enable || force_trans)
                    {
                        bot.gs_ChangeSceneByTransport(m_Data.Name, type, (msg) => { }, error);
                        return true;
                    }
                    return false;
                }
            }

        }

        public enum DungeonType
        {
            单人副本 = 1,
            组队副本 = 2,
            秘境副本 = 3,
            超级副本 = 4,
        }

        public enum DungeonLevel
        {
            普通 = 1,
            精英 = 2,
            英雄 = 3,
        }
    }
}