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.Asyncs;
using XGame.Framework.Interfaces;
using XGame.Framework.Loadable;
using XGame.Framework.Map;
using XGame.Framework.Nodes;
using XGame.Framework.Time;

namespace FL.Nodes.GameMain
{
    public class MapComponent : NodeComponent, ILoadAsyncHandle, 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.GameMainMapExchangePartner, OnExchangePartner);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapEndMask, OnMapEndMask);
            InitMonsters();
            StartMap(PlayerData.Instance.chapterId);
        }

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

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

        void ILoadAsyncHandle.OnLoadAsync(IAsyncGroup group)
        {
            ChapterTableRepo.LoadAsync().Join(group);
            MapTableRepo.LoadAsync().Join(group);
            MonsterTableRepo.LoadAsync().Join(group);
            PartnerTableRepo.LoadAsync().Join(group);
            SkillTableRepo.LoadAsync().Join(group);
            SkillVfxsTableRepo.LoadAsync().Join(group);
        }

        void ILoadAsyncHandle.OnUnloadAsync(IAsyncGroup group)
        {
            ChapterTableRepo.Unload();
            MapTableRepo.Unload();
            MonsterTableRepo.Unload();
            PartnerTableRepo.Unload();
            SkillTableRepo.Unload();
            SkillVfxsTableRepo.Unload();
        }

        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, PlayerData.Instance.activePartnerIds);
                AddPartners(partners);
                dto.partners = partners;
            }
            else if (isMapChanged)
            {
                //玩家
                dto.player = _player;
                //伙伴
                dto.partners = _partnerMap.Values.ToArray();
            }
            if (isChapterChanged)
            {
                // 重置玩家血量
                _player.Attr.Hp = _player.Attr.HpLimit;
                // 随从可能有替换过，重置随从的出生点
                var birthPosition = _player.BirthPosition;
                foreach (var partner in _partnerMap.Values)
                {
                    partner.BirthPosition = birthPosition + PlayerData.Instance.GetPartnerOffset(partner.TableId);
                }
            }
            //怪物数据
            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 attr = PlayerData.Instance.Attr;
            attr.Name = "player";
            attr.Hp = 10000;
            attr.HpLimit = 10000;
            attr.Mp = 10000;
            attr.MpLimit = 10000;
            attr.Radius = 1;
            attr.MoveSpeed = 5;
            attr.Attack = 15;
            attr.AtkRange = 3;
            attr.AttackCD = 2000;
            var player = new PlayerEntity()
            {
                BirthPosition = birth//玩家出生点
            };
            player.Init(0, UIDDefine.New(), attr, PlayerData.Instance.skillIds);
            return player;
        }
        private PartnerEntity[] GenPartners(Vector3 targetPosition, List<int> partnerIds)
        {
            var count = partnerIds.Count;
            var partners = new PartnerEntity[count];
            for (var i = 0; i < count; i++)
            {
                var tableId = partnerIds[i];
                var table = PartnerTableRepo.Get(tableId);
                var attr = new EntityAttributes()
                {
                    Name = table.Name,
                    Hp = 500,
                    HpLimit = 500,
                    Mp = 100,
                    MpLimit = 100,
                    Radius = table.Size * 0.5f,
                    MoveSpeed = PlayerData.Instance.moveSpeed,
                    Attack = Random.Range(5, 10),
                    AtkRange = PlayerData.Instance.atkRange,
                    AttackCD = 6000,
                };
                var partner = new PartnerEntity()
                {
                    BirthPosition = targetPosition + PlayerData.Instance.GetPartnerOffset(tableId)
                };
                partner.Init(table.Id, UIDDefine.New(), attr, new int[] {table.Skill});
                partners[i] = partner;
            }
            return partners;
        }
        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 attr = new EntityAttributes()
                    {
                        Name = monsterTab.Name,
                        Hp = monsterTab.Hp,
                        HpLimit = monsterTab.Hp,
                        Radius = monsterTab.ModelSize * 0.5f,
                        MoveSpeed = monsterTab.Speed,
                        Attack = monsterTab.Atk,
                        AtkRange = monsterTab.AtkRange,
                        AttackCD = 3000,
                    };
                    var entity = new MonsterEntity();
                    entity.Init(monsterRefresh[0], UIDDefine.New(), attr, 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 OnExchangePartner(int eventId, object args)
        {
            var addPartners = (List<int>)args;
            var activePartnerIds = PlayerData.Instance.activePartnerIds;
            var count = addPartners.Count;
            // 从后往前移除
            for (var i = 0; i < count; i++)
            {
                var partnerId = activePartnerIds[activePartnerIds.Count - 1];
                activePartnerIds.RemoveAt(activePartnerIds.Count - 1);
                var partnerUID = GetPartnerUIDByTableId(partnerId);
                if (partnerUID == 0)
                    continue;
                EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveEntity, partnerUID);
            }
            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 GetPartnerUIDByTableId(int tableId)
        {
            foreach(var item in _partnerMap)
            {
                if (item.Value.TableId == tableId)
                    return item.Key;
            }
            return 0;
        }
    }
}