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

namespace FL.Map.TestMainMap
{
    public interface IEntitiesContext
    {
        IMapAssetModule Asset { get; }
        ITimeModule Time { get; }
        TestMainMapVM VM { get; }
    }
    public class EntitiesComponent : Component<IEntitiesContext>, ILateUpdate
    {
        private PlayerEntityView _player;
        private Dictionary<int, PartnerEntityView> _partnerMap = new Dictionary<int, PartnerEntityView>();
        /// <summary>
        /// 怪物的实例对象
        /// </summary>
        private Dictionary<int, MonsterEntityView> _monsterMap = new Dictionary<int, MonsterEntityView>();
        private TargetSelector _selector;
        private ITimer _selectorTimer;

        public override int Order => 0;
        protected override void OnEnable(object intent)
        {
            InitSelector();
            EventSingle.Instance.AddListener(EventDefine.GameMainMapLoadEntities, OnLoadEntities);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapFindTarget, OnFindTarget);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapStartMask, OnStartMask);
        }
        protected override void OnDisable()
        {
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapLoadEntities, OnLoadEntities);
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapFindTarget, OnFindTarget);
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapStartMask, OnStartMask);
            ClearSelector();
            Context.VM.Camera.Target = null;
            Context.Asset.Recycle(_player);
            foreach (var partner in _partnerMap.Values)
            {
                Context.Asset.Recycle(partner);
            }
            _partnerMap.Clear();
            foreach (var monster in _monsterMap.Values)
            {
                Context.Asset.Recycle(monster);
            }
            _monsterMap.Clear();
        }
        protected override void OnDispose()
        {
        }
        void ILateUpdate.LateUpdate(int millisecond)
        {
            Context.VM.UpdateMapMoveTime(millisecond);
            Context.VM.Camera.OnLateUpdate(millisecond);
        }
        #region 事件监听
        private void OnLoadEntities(int eventId, object args)
        {
            var dto = (LoadEntitiesDto)args;
            var asyncGroup = new AsyncGroup();
            if (dto.player != null)
            { // 第一波怪物，玩家不存在时
                var playerAsync = Context.Asset.LoadEntity<PlayerEntityView>("Player", Context.VM.PlayerRoot);
                playerAsync.On(_ =>
                {
                    var entityView = playerAsync.Result;
                    if (entityView == null)
                    {
                        return;
                    }
                    entityView.Entity = dto.player;
                    Context.VM.Camera.Target = entityView.GetComponent<MoveComponent>();// behaviour.transform;
                    _player = entityView;
                    _selector.Register(entityView);
                });
                playerAsync.Join(asyncGroup);
            }
            else if (dto.isChapterChanged)
            {
                Context.VM.Reset();
                _player.Reset();
                foreach (var item in _partnerMap)
                {
                    item.Value.Reset();
                }
            }
            var partnerCount = dto.partners?.Length ?? 0;
            if (partnerCount > 0)
            { // 创建伙伴实例
                for (var i = 0; i < partnerCount; i++)
                {
                    var partner = dto.partners[i];
                    var table = PartnerTableRepo.Get(partner.TableId);
                    var loadAsync = Context.Asset.LoadEntity<PartnerEntityView>(table.Model, Context.VM.PlayerRoot);
                    loadAsync.On(_ =>
                    {
                        var entityView = loadAsync.Result;
                        if (entityView == null)
                        {
                            return;
                        }
                        entityView.Entity = partner;
                        entityView.BodyMirror();
                        _partnerMap.Add(partner.EntityId, entityView);
                        _selector.Register(entityView);
                    });
                    loadAsync.Join(asyncGroup);
                }
            }
            var monsterCount = dto.monsters?.Length ?? 0;
            if (monsterCount > 0)
            { // 创建怪物实例
                for (var i = 0; i < monsterCount; i++)
                {
                    var monster = dto.monsters[i];
                    var table = MonsterTableRepo.Get(monster.TableId);
                    var loadAsync = Context.Asset.LoadEntity<MonsterEntityView>(table.Model, Context.VM.EnemyRoot);
                    loadAsync.On(_ =>
                    {
                        var entityView = loadAsync.Result;
                        if (entityView == null)
                        {
                            return;
                        }
                        entityView.Entity = monster;
                        entityView.Entity = monster;
                        _monsterMap.Add(monster.EntityId, entityView);
                        _selector.Register(entityView);
                    });
                    loadAsync.Join(asyncGroup);
                }
            }
            asyncGroup.On(_ =>
            {
                //Entities加载完成，开始移动
                if (dto.isPlayerMove)
                {
                    var args = new MoveArgs
                    {
                        target = dto.battlePosition,
                        speed = _player.Entity.Attr.MoveSpeed,
                        callback = () =>
                        {
                            // 玩家移动速度快，先到目标坐标
                            _player.State = EEntityState.Alert;
                            _selector.Start(new FindTargetArgs()
                            {
                                entityId = _player.Entity.EntityId,
                                entityType = EEntityType.Monster,
                                range = 6,
                                skillId = PlayerData.Instance.skillId
                            });
                            if (dto.isChapterChanged)
                            {
                                Context.VM.SetFocusPosition(_player.Position);
                            }
                        }
                    };
                    _player.State = EEntityState.Protected;
                    _player.MoveTo(args);
                    foreach (var item in _partnerMap)
                    {
                        var entityView = item.Value;
                        var entity = entityView.Entity;
                        var table = PartnerTableRepo.Get(entity.TableId);
                        var tarPosition = dto.battlePosition;
                        tarPosition += PlayerData.Instance.GetSwordOffset((int)table.Type - 1);
                        var moveArgs = new MoveArgs
                        {
                            target = tarPosition,
                            speed = entity.Attr.MoveSpeed,
                            callback = () =>
                            {
                                entityView.State = EEntityState.Alert;
                                _selector.Start(new FindTargetArgs()
                                {
                                    entityId = entity.EntityId,
                                    entityType = EEntityType.Monster,
                                    range = entity.Attr.AtkRange,
                                    skillId = table.Skill,
                                });
                            }
                        };
                        entityView.State = EEntityState.Protected;
                        entityView.MoveTo(moveArgs);
                    }
                }
                var monsterCount = dto.monsters?.Length ?? 0;
                for (var mIdx = 0; mIdx < monsterCount; mIdx++)
                {
                    var entity = dto.monsters[mIdx];
                    //var monsterTable = MonsterTableRepo.Get(entity.TableId);
                    var tarPosition = entity.TargetPosition;
                    tarPosition.y += (-dto.monsterMoveDistance + entity.Attr.AtkRange + entity.Attr.Radius);
                    var entityView = _monsterMap[entity.EntityId];
                    var args = new MoveArgs
                    {
                        target = tarPosition,
                        speed = entity.Attr.MoveSpeed,
                        delay = dto.monsterMoveDelay,
                        callback = () =>
                        {
                            entityView.State = EEntityState.Alert;
                            _selector.Start(new FindTargetArgs()
                            {
                                entityId = entity.EntityId,
                                entityType = EEntityType.Player,
                                range = entity.Attr.AtkRange,
                                skillId = MonsterTableRepo.Get(entity.TableId).Skill,
                            });
                        }
                    };
                    entityView.State = EEntityState.Protected;
                    entityView.MoveTo(args);
                }
            });
            asyncGroup.End();
        }

        private void OnRemoveEntity(int eventId, object args)
        {
            var entityId = (int)args;
            if (_monsterMap.TryGetValue(entityId, out var entity))
            {
                _monsterMap.Remove(entityId);
                _selector?.Unregister(entity);
                Context.Asset.Recycle(entity);
                return;
            }
            if (_partnerMap.TryGetValue(entityId, out var partner))
            {
                _partnerMap.Remove(entityId);
                _selector?.Unregister(partner);
                Context.Asset.Recycle(partner);
                return;
            }
            if (entityId == _player?.Entity.EntityId)
            {
                Context.Asset.Recycle(_player);
                _selector?.Unregister(_player);
                _player = null;
            }
        }
        #endregion

        #region 目标选择
        private void InitSelector()
        {
            if (_selector == null)
            {
                _selector = new TargetSelector();
            }
            _selectorTimer = Context.Time.AddLooperTimer(100, _selector.Selects);
        }
        private void ClearSelector()
        {
            _selector?.Clear();
            _selectorTimer?.Cancel();
            _selectorTimer = null;
        }
        private void OnFindTarget(int eventId, object args)
        {
            var targetArgs = (FindTargetArgs)args;
            _selector?.Start(targetArgs);
        }
        #endregion

        #region 黑屏
        private void OnStartMask(int eventId, object args)
        {
            var duration = 2;
            PlayerMoveToCenter(duration);
            Context.VM.ShowBlackMask(duration, () =>
            {
                EventSingle.Instance.Notify(EventDefine.GameMainMapEndMask);
            });
        }
        /// <summary>
        /// 玩家移动到屏幕中心
        /// </summary>
        /// <param name="duration">单位:秒</param>
        private void PlayerMoveToCenter(float duration)
        {
            var centerPosition = Context.VM.Camera.TopCenterToWorldPosition();
            var distance = centerPosition.y - _player.Position.y;
            var speed = distance / duration;
            var targetPosition = Context.VM.PlayerRoot.InverseTransformPoint(centerPosition);
            Log.Debug($"PlayerMoveToCenter Player World:{_player.Position} Local:{_player.LocalPosition} Center World:{centerPosition} Local:{targetPosition}");
            var args = new MoveArgs
            {
                target = targetPosition,
                speed = speed,
            };
            _player.State = EEntityState.Protected;
            _player.MoveTo(args);
            foreach (var item in _partnerMap)
            {
                var entityView = item.Value;
                var entity = entityView.Entity;
                var table = PartnerTableRepo.Get(entity.TableId);
                var tarPosition = targetPosition;
                tarPosition += PlayerData.Instance.GetSwordOffset((int)table.Type - 1);
                var moveArgs = new MoveArgs
                {
                    target = tarPosition,
                    speed = speed,
                };
                entityView.State = EEntityState.Protected;
                entityView.MoveTo(moveArgs);
            }
        }
        #endregion
    }
}