using FL.Battle;
using FL.Data;
using FL.FGUI;
using FL.Map;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using XGame;
using XGame.Database;
using XGame.Framework.Interfaces;
using XGame.Framework.Map;
using XGame.Framework.Nodes;
using XGame.Framework.Time;

namespace FL.Nodes.GameMain
{
    public class MapComponent : NodeComponent, IUpdate
    {

        private int _chapterId;
        private EMapSchedule _schedule;
        private ITimer _monsterTimer;

        private PlayerEntity _player;
        /// <summary>
        /// 怪物坐标相对出生点的偏移值
        /// 怪物最多13个，分两排排列，索引如下
        /// 二排   9 5 1 2 6 10
        /// 一排 11 7 3 0 4 8 12
        /// 0的左边偏移值为负数
        /// </summary>
        private Vector3 _monsterOffset = new Vector3(0.8f, 1.5f, 0);
        /// <summary>
        /// 空闲的怪物位置索引
        /// </summary>
        private List<int> _unusedIndexs;
        /// <summary>
        /// 怪物的实例对象
        /// </summary>
        private Dictionary<long, MonsterEntity> _monsterMap;
        /// <summary>
        /// 伙伴的实例对象
        /// </summary>
        private Dictionary<long, PartnerEntity> _partnerMap;
        private MapKey _currentMap;

        public override void OnEnable(object intent)
        {
            EventSingle.Instance.AddListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapEndMask, OnMapEndMask);
            EventSingle.Instance.AddListener(EventDefine.PartnerDown, OnPartnerDown);
            EventSingle.Instance.AddListener(EventDefine.PartnerUp, OnPartnerUp);
            InitMonsters();
            StartMap(PlayerData.Instance.chapterId);
        }

        public override void OnDisable()
        {
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapEndMask, OnMapEndMask);
            EventSingle.Instance.RemoveListener(EventDefine.PartnerDown, OnPartnerDown);
            EventSingle.Instance.RemoveListener(EventDefine.PartnerUp, OnPartnerUp);
            _player = null;
            _partnerMap?.Clear();
            _monsterTimer?.Cancel();
            _monsterTimer = null;
            _monsterMap?.Clear();
            _unusedIndexs?.Clear();

            Context.Map.Close(_currentMap);
            _currentMap = null;
        }

        void IUpdate.Update(int millisecond)
        {
            if (_player == null)
                return;
        }
        private void InitMonsters()
        {
            if (_unusedIndexs == null)
                _unusedIndexs = new List<int>();
            else
                _unusedIndexs.Clear();
            for (var i = 0; i < 13; i++)
            {
                _unusedIndexs.Add(i);
            }
        }
        private void StartMap(int chapterId)
        {
            _chapterId = chapterId;
            _schedule = EMapSchedule.LoadingMap;
            var chapter = ChapterTableRepo.Get(_chapterId);
            var map = MapTableRepo.Get(chapter.Map);
            var mapKey = MapKeys.NameToKey(map.AssetName);
            if (mapKey == _currentMap)
            { // 是同一个地图
                StartChapter(true, false);
            }
            else
            {
                // 关闭当前地图
                Context.Map.Close(_currentMap);
                _currentMap = mapKey;
                // 加载新地图
                var mapAsync = Context.Map.RunAsync(mapKey);
                mapAsync.On(_ =>
                {
                    StartChapter(true, true);
                });
            }
        }
        private void StartChapter(bool isChapterChanged, bool isMapChanged)
        {
            _schedule = EMapSchedule.Monster1;
            var chapter = ChapterTableRepo.Get(_chapterId);
            var map = MapTableRepo.Get(chapter.Map);
            var dto = new LoadEntitiesDto();
            dto.chapterId = _chapterId;
            dto.isChapterChanged = isChapterChanged;
            dto.isPlayerMove = true;
            //战斗位置
            dto.battlePosition = map.BattlePositions[chapter.Part - 1].ToVector3();
            var isGenPlayer = _player == null;
            if (isGenPlayer)
            {
                _player = GenPlayer(map.PlayerBirth.ToVector3());
                //玩家
                dto.player = _player;
                //伙伴
                var partners = GenPartners(_player.BirthPosition);
                AddPartners(partners);
                dto.partners = partners;
            }
            else if (isMapChanged)
            {
                //玩家
                dto.player = _player;
                //伙伴
                dto.partners = _partnerMap.Values.ToArray();
            }
            if (isChapterChanged)
            {
                // 重置玩家血量
                _player.Attr.Dynamic.Clear();
                _player.Attr.ResetHp();
                // 随从可能有替换过，重置随从的出生点
                var birthPosition = _player.BirthPosition;
                foreach (var partner in _partnerMap.Values)
                {
                    partner.BirthPosition = birthPosition + PartnersData.Instance.GetPartnerOffset(partner.Attr.UID);
                }
            }
            //怪物数据
            var monsters = GenMonsters();
            AddMonsters(monsters);
            dto.monsters = monsters;
            dto.monsterMoveDistance = map.MonsterPositions[chapter.Part - 1].ToVector3().y - dto.battlePosition.y;
            //定时器
            if (chapter.Part_type == 0)
            { // 普通节点，增加定时器
                dto.monsterMoveDelay = 0;
                _monsterTimer = Context.Time.AddDelayLooperTimer(chapter.Interval * 6, chapter.Interval * 6, OnLoopGenMonsters);
            }
            else
            { // boss关卡，直接到最后
                dto.monsterMoveDelay = 1000;
                _schedule = EMapSchedule.Monster5;
                Context.UI.OpenAsync(UIKeys.MainBossLaiXi);
                Context.Time.AddDelayTimer(1000, () =>
                { //1秒后自动关闭
                    Context.UI.Close(UIKeys.MainBossLaiXi);
                });
            }
            EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto);

        }
        private void OnLoopGenMonsters(int times)
        {
            _schedule += 1;
            if (_schedule == EMapSchedule.Monster5)
            {
                _monsterTimer.Cancel();
                _monsterTimer = null;
            }
            var chapter = ChapterTableRepo.Get(_chapterId);
            var map = MapTableRepo.Get(chapter.Map);
            var dto = new LoadEntitiesDto();
            dto.chapterId = _chapterId;
            //战斗位置
            dto.battlePosition = map.BattlePositions[chapter.Part - 1].ToVector3();
            //怪物数据
            var monsters = GenMonsters();
            AddMonsters(monsters);
            dto.monsters = monsters;
            dto.monsterMoveDistance = map.MonsterPositions[chapter.Part - 1].ToVector3().y - dto.battlePosition.y;
            EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto);
        }
        private PlayerEntity GenPlayer(Vector3 birth)
        {
            var playerData = PlayerData.Instance;
            var player = new PlayerEntity()
            {
                BirthPosition = birth//玩家出生点
            };
            var entityAttr = new EntityAttributes(0, playerData.UID)
            {
                Name = playerData.Name,
                Radius = 1,
                AttackCD = 2000,
            };
            entityAttr.CopyFrom(playerData.Attr);
            player.Init(UIDDefine.New(), entityAttr, playerData.skillIds);
            return player;
        }
        private PartnerEntity[] GenPartners(Vector3 targetPosition)
        {
            var goneUpMap = PartnersData.Instance.GoneUpMap;
            var count = goneUpMap.Count;
            var partners = new PartnerEntity[count];
            var index = 0;
            foreach (var partnerUID in goneUpMap.Keys)
            {
                partners[index++] = GenPartner(targetPosition, partnerUID);
            }
            return partners;
        }
        private PartnerEntity GenPartner(Vector3 targetPosition, long partnerId)
        {
            var partner = PartnersData.Instance.PartnersMap[partnerId];
            var entity = new PartnerEntity()
            {
                BirthPosition = targetPosition + PartnersData.Instance.GetPartnerOffset(partner.UID),
                EpigraphId = 20300,
            };
            var entityAttr = new EntityAttributes(partner.TableId, partner.UID)
            {
                Name = partner.Name,
                Radius = partner.Radius,
                AttackCD = 6000,
            };
            entityAttr.CopyFrom(partner.Attr);
            var table = PartnerTableRepo.Get(partner.TableId);
            entity.Init(UIDDefine.New(), entityAttr, new int[] { table.Skill });
            return entity;
        }
        private void AddPartners(PartnerEntity[] partners)
        {
            if (partners == null || partners.Length == 0) return;
            if (_partnerMap == null)
            {
                _partnerMap = new Dictionary<long, PartnerEntity>();
            }
            foreach (var partner in partners)
            {
                _partnerMap.Add(partner.EntityId, partner);
            }
        }
        /// <summary>
        /// 获取怪物的出生坐标和索引
        /// </summary>
        /// <param name="position"></param>
        /// <param name="positionIdx"></param>
        /// <returns></returns>
        private Vector3 GetMonsterBirth(Vector3 position, out int positionIdx)
        {
            if (_unusedIndexs.Count > 0)
            {
                positionIdx = _unusedIndexs[0];
                _unusedIndexs.RemoveAt(0);
            }
            else
            {
                positionIdx = 0;
            }
            if (positionIdx == 0)
            {
                return position;
            }
            var offset = Vector3.zero;
            var xMultiple = (positionIdx + 1) / 2;
            offset.x = _monsterOffset.x * xMultiple;
            if (positionIdx % 2 != 0)
            { // 索引为奇数的在左边
                offset.x = -offset.x;
            }
            if (xMultiple % 2 != 0)
            { // 倍数为奇数的在上面
                offset.y = _monsterOffset.y;
            }
            var target = position + offset;
            // 随机偏移xy(-0.2, 0.2)
            target.x += Random.Range(-0.25f, 0.25f);
            target.y += Random.Range(-0.25f, 0.25f);
            return target;
        }
        private void PushMonstPositionIdx(int positionIdx)
        {
            if (_unusedIndexs.Contains(positionIdx))
                return; // 避免重复记录
            for (var i = 0; i < _unusedIndexs.Count; i++)
            {
                if (positionIdx < _unusedIndexs[i] && (i == 0 || positionIdx > _unusedIndexs[i - 1]))
                { // 小于当前索引的值 且 大于(i - 1 )的值
                    _unusedIndexs.Insert(i, positionIdx);
                    return;
                }
            }
            _unusedIndexs.Add(positionIdx);
        }
        private MonsterEntity[] GenMonsters()
        {
            var chapter = ChapterTableRepo.Get(_chapterId);
            var map = MapTableRepo.Get(chapter.Map);
            Vector3 birthPosition = map.MonsterPositions[chapter.Part - 1].ToVector3();
            int[] monsterRefresh = null;
            switch (_schedule)
            {
                case EMapSchedule.Monster1:
                    monsterRefresh = chapter.Monster_refresh1;
                    break;
                case EMapSchedule.Monster2:
                    monsterRefresh = chapter.Monster_refresh2;
                    break;
                case EMapSchedule.Monster3:
                    monsterRefresh = chapter.Monster_refresh3;
                    break;
                case EMapSchedule.Monster4:
                    monsterRefresh = chapter.Monster_refresh4;
                    break;
                case EMapSchedule.Monster5:
                    monsterRefresh = chapter.Monster_refresh5;
                    break;
                default:
                    break;
            }
            var monsterCount = (monsterRefresh != null && monsterRefresh.Length > 0) ? monsterRefresh[1] : 0;
            if (monsterCount > 0)
            { // 数量0-3
                var monsters = new MonsterEntity[monsterCount];
                for (var i = 0; i < monsterCount; i++)
                {
                    var position = GetMonsterBirth(birthPosition, out var positionIdx);
                    var monsterTab = MonsterTableRepo.Get(monsterRefresh[0]);
                    var entityAttr = new EntityAttributes(monsterTab.Id, UIDDefine.New())
                    {
                        Name = monsterTab.Name,
                        Radius = monsterTab.ModelSize * 0.5f,
                        AttackCD = 3000,
                    };
                    entityAttr.Static.Hp = monsterTab.Hp;
                    entityAttr.Static.HpLimit = monsterTab.Hp;
                    entityAttr.Static.MoveSpeed = Mathf.RoundToInt(monsterTab.Speed);
                    entityAttr.Static.Attack = monsterTab.Atk;
                    entityAttr.CurrentHp = monsterTab.Hp;
                    var entity = new MonsterEntity();
                    entity.Init(UIDDefine.New(), entityAttr, monsterTab.Skills);
                    entity.BirthPosition = position;
                    entity.PositionIdx = positionIdx;
                    monsters[i] = entity;
                }
                return monsters;
            }
            return null;
        }
        private void AddMonsters(MonsterEntity[] monsters)
        {
            if (monsters == null || monsters.Length == 0) return;
            if (_monsterMap == null)
            {
                _monsterMap = new Dictionary<long, MonsterEntity>();
            }
            foreach (var monsterInfo in monsters)
            {
                _monsterMap.Add(monsterInfo.EntityId, monsterInfo);
            }
        }
        #region 事件监听
        private void OnRemoveEntity(int eventId, object args)
        {
            var entityId = (long)args;
            if (_monsterMap.TryGetValue(entityId, out var entity))
            {
                _monsterMap.Remove(entityId);
                PushMonstPositionIdx(entity.PositionIdx);
                CheckMonsterAllDead();
                return;
            }
            if (_partnerMap.TryGetValue(entityId, out var partner))
            {
                _partnerMap.Remove(entityId);
                return;
            }
            if (entityId == _player.EntityId)
            {
                _player = null;
                //TODO 失败结算
            }
        }
        private void OnPartnerDown(int eventId, object args)
        {
            var partnerUID = (long)args;
            var entityId = GetPartnerEntityIdByUID(partnerUID);
            if (entityId == 0)
                return;
            EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveEntity, entityId);
        }
        private void OnPartnerUp(int eventId, object args)
        {
            var partnerUID = (long)args;
            var entityId = GetPartnerEntityIdByUID(partnerUID);
            if (entityId != 0)
                return; // 已经有实例对象了
            var chapter = ChapterTableRepo.Get(_chapterId);
            var map = MapTableRepo.Get(chapter.Map);
            var dto = new LoadEntitiesDto();
            dto.chapterId = _chapterId;
            //战斗位置
            dto.battlePosition = map.BattlePositions[chapter.Part - 1].ToVector3();
            var partner = GenPartner(dto.battlePosition, partnerUID);
            var partners = new PartnerEntity[] { partner };
            AddPartners(partners);
            dto.partners = partners;
            EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto);
        }
        //private void OnExchangePartner(int eventId, object args)
        //{
        //    var addPartners = (List<int>)args;
        //    var activePartnerIds = PartnersData.Instance.ActiveUIDs;
        //    var count = addPartners.Count;
        //    // 从后往前移除
        //    for (var i = 0; i < count; i++)
        //    {
        //        var partnerId = activePartnerIds[activePartnerIds.Count - 1];
        //        activePartnerIds.RemoveAt(activePartnerIds.Count - 1);
        //        var EntityId = GetPartnerUIDByTableId(partnerId);
        //        if (EntityId == 0)
        //            continue;
        //        EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveEntity, EntityId);
        //    }
        //    activePartnerIds.AddRange(addPartners);
        //    var chapter = ChapterTableRepo.Get(_chapterId);
        //    var map = MapTableRepo.Get(chapter.Map);
        //    var dto = new LoadEntitiesDto();
        //    dto.chapterId = _chapterId;
        //    //战斗位置
        //    dto.battlePosition = map.BattlePositions[chapter.Part - 1].ToVector3();
        //    var partners = GenPartners(dto.battlePosition, addPartners);
        //    AddPartners(partners);
        //    dto.partners = partners;
        //    EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto);
        //}
        private void OnMapEndMask(int eventId, object args)
        {
            var chapter = ChapterTableRepo.Get(_chapterId);
            var nextChapter = ChapterTableRepo.Next(_chapterId);
            //没找到新关卡，重新开始
            if (nextChapter == null || nextChapter.Chapter != chapter.Chapter)
            { // 没有新关卡 || 章节id变化
              //TODO 章节切换
            }
            var chapterId = nextChapter?.Id ?? PlayerData.Instance.chapterId;
            StartMap(chapterId);
        }
        #endregion
        private void CheckMonsterAllDead()
        {
            if (_monsterMap.Count > 0) return;
            // 怪物全部死亡
            var chapter = ChapterTableRepo.Get(_chapterId);
            if (chapter.Part_type == 1)
            { //boss关卡
                //TODO 结算
                Context.UI.OpenAsync(UIKeys.MainBattleOverVictory);
                Context.Time.AddDelayTimer(2000, () =>
                { //2秒后自动关闭
                    Context.UI.Close(UIKeys.MainBattleOverVictory);
                    EventSingle.Instance.Notify(EventDefine.GameMainMapStartMask);
                });
            }
            else if (_schedule == EMapSchedule.Monster5)
            {
                _chapterId++;
                StartChapter(false, false);
            }
        }
        private long GetPartnerEntityIdByUID(long uid)
        {
            foreach (var item in _partnerMap)
            {
                if (item.Value.Attr.UID == uid)
                    return item.Key;
            }
            return 0;
        }
    }
}