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

namespace FL.Nodes.GameMain
{
    public class MapComponent : NodeComponent, ILoadAsyncHandle, IUpdate
    {
        /// <summary>
        /// 怪物的实例Id，自增
        /// </summary>
        private static int Entity_Id_Add = 0;
        private int _chapterId;
        private EMapSchedule _schedule;
        private ITimer _monsterTimer;

        private PlayerEntity _player;
        /// <summary>
        /// _offsets[0] 中间位置的偏移次数
        /// _offsets[1] 左右位置的偏移次数
        /// </summary>
        private int[] _offsets;
        /// <summary>
        /// 怪物的实例对象
        /// </summary>
        private Dictionary<int, MonsterEntity> _monsterMap;
        /// <summary>
        /// 伙伴的实例对象
        /// </summary>
        private Dictionary<int, PartnerEntity> _partnerMap;

        public override void OnEnable(object intent)
        {
            EventSingle.Instance.AddListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);

            _chapterId = PlayerData.Instance.chapterId;
            _schedule = EMapSchedule.LoadingMap;
            var chapter = ChapterTableRepo.Get(_chapterId);
            var map = MapTableRepo.Get(chapter.Map);
            var mapAsync = Context.Map.RunAsync(MapKeys.NameToKey(map.AssetName));
            mapAsync.On(_ =>
            {
                StartChapter();
            });
        }
        public override void OnDisable()
        {
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
            _player = null;
            _partnerMap?.Clear();
            _monsterTimer?.Cancel();
            _monsterTimer = null;
            _monsterMap?.Clear();
            Context.Map.Close(MapKeys.TestMainMap);
        }

        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);
        }

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

        void IUpdate.Update(int millisecond)
        {
            if (_player == null)
                return;
        }
        private void StartChapter()
        {
            _schedule = EMapSchedule.Monster1;
            _offsets = new int[]{ 0, 0 };
            var chapter = ChapterTableRepo.Get(_chapterId);
            var map = MapTableRepo.Get(chapter.Map);
            var dto = new LoadEntitiesDto();
            dto.chapterId = _chapterId;
            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.TargetPosition);
                AddPartners(partners);
                dto.partners = partners;
            }
            //怪物数据
            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)
            { // 普通节点，增加定时器
                _monsterTimer = Context.Time.AddDelayLooperTimer(chapter.Interval * 6, chapter.Interval * 6, OnLoopGenMonsters);
            }
            else
            { // boss关卡，直接到最后
                _schedule = EMapSchedule.Monster5;
            }
            EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto);

        }
        private void OnLoopGenMonsters()
        {
            _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()
            {
                TargetPosition = birth//玩家出生点
            };
            player.Init(0, Entity_Id_Add++, attr);
            return player;
        }
        private PartnerEntity[] GenPartners(Vector3 targetPosition)
        {
            var tables = PartnerTableRepo.GetAll();
            var count = tables.Length;
            var partners = new PartnerEntity[count];
            for (var i = 0; i < count; i++)
            {
                var table = tables[i];
                var attr = new EntityAttributes()
                {
                    Name = table.Name,
                    Hp = 500,
                    HpLimit = 500,
                    Mp = 100,
                    MpLimit = 100,
                    Radius = table.Size,
                    MoveSpeed = table.MoveSpeed,
                    Attack = Random.Range(5, 10),
                    AtkRange = table.AtkRange,
                    AttackCD = table.AttackCD,
                };
                var partner = new PartnerEntity()
                {
                    TargetPosition = targetPosition + PlayerData.Instance.GetSwordOffset(i)
                };
                partner.Init(table.Id, Entity_Id_Add++, attr);
                partners[i] = partner;
            }
            return partners;
        }
        private void AddPartners(PartnerEntity[] partners)
        {
            if (partners == null || partners.Length == 0) return;
            if (_partnerMap == null)
            {
                _partnerMap = new Dictionary<int, PartnerEntity>();
            }
            foreach (var partner in partners)
            {
                _partnerMap.Add(partner.EntityId, partner);
            }
        }

        private MonsterEntity[] GenMonsters()
        {
            var chapter = ChapterTableRepo.Get(_chapterId);
            var map = MapTableRepo.Get(chapter.Map);
            Vector3 monsterPosition = 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 xStart = monsterCount == 1 ? 0 : -2;
                var xStep = monsterCount == 2 ? 4 : 2;
                var monsters = new MonsterEntity[monsterCount];
                for (var i = 0; i < monsterCount; i++)
                {
                    var position = monsterPosition;
                    position.x = xStart + xStep * i;
                    // 二次偏移
                    if (monsterCount == 1 || (monsterCount == 3 && i == 1))
                    { // 中间位置
                        _offsets[0] += 1;
                    }
                    else
                    { // 左右
                        var offset = _offsets[1];
                        position.x += offset * 0.5f * (i == 0 ? 1 : -1);
                        position.y -= offset * 0.5f;
                        if (i > 0) 
                        {
                            _offsets[1] += 1;
                        }
                    }

                    var monsterTab = MonsterTableRepo.Get(monsterRefresh[0]);
                    var attr = new EntityAttributes()
                    {
                        Name = monsterTab.Name,
                        Hp = monsterTab.Hp,
                        HpLimit = monsterTab.Hp,
                        Radius = monsterTab.ModelSize,
                        MoveSpeed = monsterTab.Speed,
                        Attack = monsterTab.Atk,
                        AtkRange = monsterTab.AtkRange,
                        AttackCD = 3000,
                    };
                    var entity = new MonsterEntity();
                    entity.Init(monsterRefresh[0], Entity_Id_Add++, attr);
                    entity.TargetPosition = position;
                    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<int, MonsterEntity>();
            }
            foreach (var monsterInfo in monsters)
            {
                _monsterMap.Add(monsterInfo.EntityId, monsterInfo);
            }
        }
        #region 事件监听
        private void OnRemoveEntity(int eventId, object args)
        {
            var entityId = (int)args;
            if (_monsterMap.TryGetValue(entityId, out var entity))
            {
                _monsterMap.Remove(entityId);
                CheckMonsterAllDead();
                return;
            }
            if (_partnerMap.TryGetValue(entityId, out var partner))
            {
                _partnerMap.Remove(entityId);
                return;
            }
            if (entityId == _player.EntityId)
            {
                _player = null;
                //TODO 失败结算
            }
        }
        #endregion
        private void CheckMonsterAllDead()
        {
            if (_monsterMap.Count > 0) return;
            // 怪物全部死亡
            var chapter = ChapterTableRepo.Get(_chapterId);
            if (chapter.Part_type == 1)
            { //boss关卡
                //TODO 结算
            }
            else if (_schedule == EMapSchedule.Monster5)
            {
                _chapterId++;
                StartChapter();

            }
        }
    }
}