using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace ET.Server
{
    /// <summary>
    /// 地图工具类
    /// </summary>
    public static class MapHelper
    {
        /// <summary>
        /// 实际切换地图
        /// </summary>
        /// <param name="player"></param>
        /// <param name="areaData"></param>
        /// <param name="forceChange"></param>
        /// <returns></returns>
        public static Map ChangeArea(WNPlayer player, AreaData areaData, bool forceChange)
        {
            Map map = player.Map;

            if (map != null)
            {
                if (map.Id == areaData.instanceId)
                {
                    Log.Info($"changeArea1已在场景:{map.Prop.Name}, playerId={player.GetId()}, playerName={player.GetName()}");
                    return map;
                }

                map.SyncPlayerHistoryData(player);
            }

            Map targetMap = player.DomainScene().GetComponent<GameMapComponent>().Get(areaData.instanceId);
            if (targetMap == null)
            {
                Log.Debug($"目标场景为空");
                return null;
            }

            // 非强制切图,检测一下pk模式,是否允许切图
            if (!forceChange)
            {
                int resCode = player.GetXmdsManager().refreshPlayerPKMode(player.GetId().ToString().Trim(), true, (int)PkModel.Peace);
                if (resCode != 0)
                {
                    // 战斗状态下无法传送
                    Log.Warning($"refreshPlayerPKMode resCode={resCode}, playerId={player.GetId()}, 当前场景={player.GetComponent<PlayerTempDataComponent>().MapData.mapId}, 传送场景={areaData.areaId}");
                    return null;
                }
            }
            player.GetComponent<PlayerTempDataComponent>().SyncBornData(areaData.targetX, areaData.targetY, areaData.areaId);
            player.BornType = (int) BORN_TYPE.BORN;
            player.EnterState = (int) ENTER_STATE.changeArea;
            // 进入新的地图
            map = PlayerEnterAreaServer(player, areaData.instanceId);
            return map;
        }

        /// <summary>
        /// 进入map
        /// </summary>
        /// <param name="player"></param>
        /// <param name="instanceId"></param>
        public static Map PlayerEnterAreaServer(WNPlayer player, long instanceId)
        {
            Map map = player.DomainScene().GetComponent<GameMapComponent>().Get(instanceId);
            if (map != null)
            {
                Map oldMap = player.Map;
                if (oldMap != null)
                {
                    oldMap.RemovePlayer(player, false);
                }

                // 初始化角色出生坐标数据
                player.InitBornData();

                map.AddPlayer(player);
            }
            else
            {
                Log.Warning($"playerEnterAreaServer场景不存在: playerId={player.GetId()}, instanceId={instanceId}");
            }

            return map;
        }

        /// <summary>
        /// 角色bind的时候分配场景
        /// </summary>
        /// <param name="player"></param>
        /// <returns></returns>
        public static Map BindPlayerDispatch(WNPlayer player)
        {
            Map map = null;

            GameMapComponent component = player.DomainScene().GetComponent<GameMapComponent>();

            map = component.GetMapByRoomId(player.GetRoomId());

            // 老场景
            if (map != null)
            {
                // 下一局
                if (map.IsGameOver())
                {
                    map.Init();
                }
                return map;
            }

            // 创建一个场景
            JObject jsonObject = new JObject();
            jsonObject.Add("id", player.GetId());
            jsonObject.Add("logicServerId", player.GetLogicServerId());
            jsonObject.Add("areaId", 10098);
            map = CreateMap(player, jsonObject, false);

            if (map != null)
            {
                map = ChangeArea(player, new AreaData(10098, map.Id), false);
            }

            return map;
        }

        /// <summary>
        /// 创建战斗服场景需求数据
        /// </summary>
        /// <param name="player"></param>
        /// <param name="jObject"></param>
        /// <param name="forceCreate"></param>
        /// <returns></returns>
        public static Map CreateMap(WNPlayer player, JObject jObject, bool forceCreate)
        {
            Log.Debug($"createArea areaData:{JsonConvert.SerializeObject(jObject, Formatting.Indented)}");
            int mapId = Convert.ToInt32(jObject.SelectToken("areaId"));
            MapConfig prop = MapConfigCategory.Instance.Get(mapId);
            if (prop == null)
            {
                return null;
            }

            long instanceId = IdGenerater.Instance.GenerateInstanceId();
            bool usespaceDiv = prop.Type == (int) MapType.NORMAL;

            JObject jsonObject = new ();
            jsonObject.Add("monsterHard", prop.MonsterHard);
            jsonObject.Add("calPKValue", prop.ignorePkRule == 0);
            jsonObject.Add("allowAutoGuard", prop.AutoFight);
            jsonObject.Add("usespaceDiv", usespaceDiv);
            jsonObject.Add("sceneType", prop.Type);
            jsonObject.Add("areaType", prop.AreaType);
            jsonObject.Add("canRiding", prop.RideMount == 1);
            jsonObject.Add("killInterval", prop.killInterval);
            jsonObject.Add("killFullNum", prop.killFullNum);
            jsonObject.Add("killFullCollSec", prop.killFullCollSec);

            jsonObject.Add("averageLevel", 0);

            string enterData = JsonConvert.SerializeObject(jsonObject, Formatting.Indented);

            Log.Info($"createArea instanceId:{instanceId}, templateId:{prop.TemplateID}, bs:{player.GetZoneManager()}");

            int resCode = player.GetZoneManager().createZoneRequest(player.GetId().ToString(),
                "bs-" + ConstGame.GameServerId, prop.TemplateID, instanceId.ToString(), forceCreate, enterData);

            if (resCode == 0)
            {
                jsonObject.Add("instanceId", instanceId);
                jsonObject.Add("areaId", mapId);
                return CreaLocalMap(player, prop, jsonObject, instanceId, mapId, "bs-" + ConstGame.GameServerId);
            }

            Log.Warning($"createZoneRequest resCode={resCode}, mapID={prop.Id}, playerId={player.GetId()}");

            return null;
        }

        /// <summary>
        /// 创建本地场景
        /// </summary>
        /// <param name="player"></param>
        /// <param name="prop"></param>
        /// <param name="data"></param>
        /// <param name="instanceId"></param>
        /// <param name="mapId"></param>
        /// <param name="bsServerId"></param>
        /// <returns></returns>
        public static Map CreaLocalMap(WNPlayer player, MapConfig prop, JObject data, long instanceId, int mapId, string bsServerId)
        {
            Scene scene = player.DomainScene();

            Map map = scene.GetComponent<GameMapComponent>().AddChildWithId<Map, JObject, WNPlayer>(instanceId, data, player);
            if (map != null)
            {
                Log.Info($"创建Area场景:{map.MapId}, instanceId:{instanceId}, srvId:" + map.LogicServerId);
                map.BindBattleServer(player, bsServerId);
                scene.GetComponent<GameMapComponent>().Add(map.RoomId, map);
            }
            else
            {
                Log.Error($"createZone:{mapId} fail! there is no area type of this,type:{prop.Type}");
            }

            return map;
        }
    }
}