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

namespace FL.Map.TestMainMap
{
    public interface IEntitiesContext
    {
        IMapAssetModule Asset { get; }
        ITimeModule Time { get; }
        TestMainMapVM VM { get; }
        VfxComponent Vfx { get; }
        MapUIComponent MapUI { get; }
    }
    public partial class EntitiesComponent : Component<IEntitiesContext>
    {
        /// <summary>
        /// 怪物的位置相对于玩家战斗位置的偏移值
        /// </summary>
        private const float MONSTER_POSITION_OFFSET = 6;
        private PlayerEntityView _player;
        private Dictionary<long, PartnerEntityView> _partnerMap = new();
        private Dictionary<long, MonsterEntityView> _monsterMap = new();
        /// <summary>
        /// 地图实例对象，怪物、陷阱、召唤兽等
        /// key:UID
        /// </summary>
        private Dictionary<long, IEntityView> _entityViewsMap = new();
        private TargetSelector _selector;
        private ITimer _selectorTimer;

        protected override void OnEnable(object intent)
        {
            InitSelector();
            EventSingle.Instance.AddListener(EventDefine.GameMainMapLoadEntities, OnLoadEntities);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapRemoveSimpleEntity, OnRemoveSimpleEntity);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapStartMask, OnStartMask);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapGenBullet, OnGenBullet);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapGenCommons, OnGenCommons);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapAddBuff, OnAddBuff);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapRemoveBuff, OnRemoveBuff);
            EventSingle.Instance.AddListener(EventDefine.GameMainMapReqPreviewBuffs, OnRequestBuffList);
        }
        protected override void OnDisable()
        {
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapLoadEntities, OnLoadEntities);
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapRemoveSimpleEntity, OnRemoveSimpleEntity);
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapStartMask, OnStartMask);
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapGenBullet, OnGenBullet);
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapGenCommons, OnGenCommons);
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapAddBuff, OnAddBuff);
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapRemoveBuff, OnRemoveBuff);
            EventSingle.Instance.RemoveListener(EventDefine.GameMainMapReqPreviewBuffs, OnRequestBuffList);
            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();
            foreach (var entity in _entityViewsMap.Values)
            {
                Context.Asset.Recycle(entity);
            }
            _entityViewsMap.Clear();
            ClearElementBuffs();
        }
        protected override void OnDispose()
        {
        }
        #region 事件监听
        private void OnLoadEntities(int eventId, object args)
        {
            var dto = (LoadEntitiesDto)args;
            if (dto.isPlayerMove)
            {
                ClearVfxs();
            }
            var asyncGroup = new AsyncGroup();
            if (dto.player != null)
            { // 第一波怪物，玩家不存在时
                var playerAsync = Context.Asset.LoadEntity<PlayerEntityView>(AddressableDefine.Player, Context.VM.PlayerRoot);
                playerAsync.On(_ =>
                {
                    var entityView = playerAsync.Result;
                    if (entityView == null)
                    {
                        return;
                    }
                    entityView.Entity = dto.player;
                    Context.VM.Camera.Target = entityView.Move;// behaviour.transform;
                    _player = entityView;
                    _selector.Register(entityView);
                    entityView.Selector = _selector;
                    Context.MapUI.AddEntity(entityView);
                });
                playerAsync.Join(asyncGroup);
            }
            else if (dto.isChapterChanged)
            {
                Context.VM.Reset();
                _player.Reset();
                Context.MapUI.RefreshEntity(_player.Entity.EntityId);
                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);
                        entityView.Selector = _selector;
                    });
                    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);
                        entityView.Selector = _selector;
                        Context.MapUI.AddEntity(entityView);
                    });
                    loadAsync.Join(asyncGroup);
                }
            }
            asyncGroup.On(_ =>
            {
                //Entities加载完成，开始移动
                if (dto.isPlayerMove)
                {
                    _player.Reset(true);
                    _player.CommonAI.MoveToBattle(Context.VM.PlayerRoot.TransformPoint(dto.battlePosition), 0, () =>
                    {
                        if (dto.isChapterChanged)
                        {
                            Context.VM.SetFocusPosition(_player.Position);
                        }
                    });
                    foreach (var item in _partnerMap)
                    {
                        var entityView = item.Value;
                        var entity = entityView.Entity;
                        var tarPosition = dto.battlePosition;
                        tarPosition += PartnersData.Instance.GetPartnerOffset(entity.Attr.UID);
                        // 本地坐标转世界坐标
                        tarPosition = Context.VM.PlayerRoot.TransformPoint(tarPosition);
                        entityView.Reset(true);
                        entityView.CommonAI.MoveToBattle(tarPosition);
                    }
                }
                else if (partnerCount > 0)
                {
                    for (var pIdx = 0; pIdx < partnerCount; pIdx++)
                    {
                        var entity = dto.partners[pIdx];
                        var entityView = _partnerMap[entity.EntityId];
                        entityView.CommonAI.PrepareBattle();
                    }
                }
                //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.BirthPosition;
                    tarPosition.y += (-dto.monsterMoveDistance + MONSTER_POSITION_OFFSET);
                    tarPosition = Context.VM.EnemyRoot.TransformPoint(tarPosition);
                    var entityView = _monsterMap[entity.EntityId];
                    entityView.CommonAI.MoveToBattle(tarPosition, dto.monsterMoveDelay);
                }
            });
            asyncGroup.End();
        }

        private void OnRemoveEntity(int eventId, object args)
        {
            var entityId = (long)args;
            if (_monsterMap.TryGetValue(entityId, out var monster))
            {
                _monsterMap.Remove(entityId);
                _selector?.Unregister(monster);
                Context.Asset.Recycle(monster);
                RemoveElementBuff(entityId);
                return;
            }
            if (_partnerMap.TryGetValue(entityId, out var partner))
            {
                _partnerMap.Remove(entityId);
                _selector?.Unregister(partner);
                Context.Asset.Recycle(partner);
                return;
            }
            if (entityId == _player?.Entity.EntityId)
            {
                _selector?.Unregister(_player);
                Context.Asset.Recycle(_player);
                _player = null;
                Context.VM.Camera.Target = null;
            }
        }
        private void OnRemoveSimpleEntity(int eventId, object args)
        {
            var entityId = (long)args;
            if (_entityViewsMap.TryGetValue(entityId, out var entityView))
            {
                _entityViewsMap.Remove(entityId);
                Context.Asset.Recycle(entityView);
            }
        }
        #endregion

        #region 目标选择
        private void InitSelector()
        {
            if (_selector == null)
            {
                _selector = new TargetSelector();
            }
            _selectorTimer = Context.Time.AddLooperTimer(100, _selector.OnUpdate);
        }
        private void ClearSelector()
        {
            _selector?.Clear();
            _selectorTimer?.Cancel();
            _selectorTimer = null;
        }
        #endregion

        #region 黑屏
        private void OnStartMask(int eventId, object args)
        {
            var duration = 2;
            // 这时候已经没有怪物了，直接清空所有特效
            ClearVfxs();
            PlayerMoveToCenter(duration);
            Context.VM.ShowBlackMask(duration, () =>
            {
                EventSingle.Instance.Notify(EventDefine.GameMainMapEndMask);
            });
        }
        /// <summary>
        /// 没有怪物了，直接清空所有特效
        /// </summary>
        private void ClearVfxs()
        {
            foreach (var item in _entityViewsMap)
            {
                Context.Asset.Recycle(item.Value);
            }
            _entityViewsMap.Clear();
            Context.Vfx.Stop();
        }
        /// <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;
            // 使用玩家世界坐标的z值
            centerPosition.z = _player.Position.z;
            //var targetPosition = Context.VM.PlayerRoot.InverseTransformPoint(centerPosition);
            //Log.Debug($"PlayerMoveToCenter Player World:{_player.Position} Local:{_player.LocalPosition} Center World:{centerPosition}");
            _player.CommonAI.MoveTo(new MoveArgs
            {
                target = centerPosition,
                speed = speed,
                timeScale = 1,
            });
            foreach (var item in _partnerMap)
            {
                var entityView = item.Value;
                var entity = entityView.Entity;
                var tarPosition = centerPosition;
                tarPosition += PartnersData.Instance.GetPartnerOffset(entity.Attr.UID);
                entityView.CommonAI.MoveTo(new MoveArgs
                {
                    target = tarPosition,
                    speed = speed,
                    timeScale = 1,
                });
            }
        }
        #endregion

        #region 子弹
        private void OnGenBullet(int eventId, object args)
        {
            var dto = (GenBulletDto)args;
            var targetType = dto.masterType == EEntityType.Monster ? EEntityType.Player : EEntityType.Monster;
            var skill = SkillTableRepo.Get(dto.tableId);
            var skillVfx = SkillVfxsTableRepo.Get(dto.tableId);
            var loadAsync = Context.Asset.LoadEntity<BulletEntityView>(skillVfx.SkillVfx, Context.VM.BulletRoot);
            var startTime = Context.Time.GetNowTime();
            loadAsync.On(_ =>
            {
                var delay = dto.delay > 0 ? Mathf.Max(dto.delay - (int)(Context.Time.GetNowTime() - startTime), 0) : 0;
                var view = loadAsync.Result;
                if (view == null)
                    return;
                //var tarEntity = _selector.GetTarget((int)dto.targetId);
                //if (tarEntity == null || tarEntity.Entity.State == EEntityState.Dead)
                //{
                //    Context.Asset.Recycle(view);
                //    Log.Debug($"子弹加载成功，但是目标已死亡。Master:{dto.masterId} Target:{dto.targetId} Bullet:{dto.tableId}");
                //    return;
                //}
                view.UID = UIDDefine.New();
                view.MasterId = dto.masterId;
                view.TableId = dto.tableId;
                view.Selector = _selector;
                view.Position = dto.from;
                _entityViewsMap.Add(view.UID, view);
                var tarPosition = dto.to;
                if (skill.SkillVfxType == (int)ESkillVfxType.BulletMortar)
                { // 目标位置随机，以本节战斗位置为中心偏移
                    tarPosition = _player.Position; //玩家的坐标和本节战斗的位置重叠
                    if (dto.masterType != EEntityType.Monster)
                    {// 施法者是玩家或者随从
                        tarPosition += skillVfx.SkillVfxPositions[1].ToVector3();
                    }
                    tarPosition.x += UnityEngine.Random.Range(-4, 5);
                    tarPosition.y += UnityEngine.Random.Range(-2, 2);
                }
                view.AI.Start(dto.targetId, tarPosition, targetType, delay);
            });
        }
        #endregion
        #region 召唤物
        private void OnGenCommons(int eventId, object args)
        {
            var dto = (GenSummonsDto)args;
            var skill = SkillTableRepo.Get(dto.tableId);
            var skillVfxs = SkillVfxsTableRepo.Get(dto.tableId);
            //var targetType = dto.masterType == EEntityType.Monster ? EEntityType.Player : EEntityType.Monster;
            var battlePosition = _player.Position;//玩家的坐标和本节战斗的位置重叠
            for (var i = 0; i < dto.count; i++)
            {
                switch ((ESkillVfxType)skill.SkillVfxType)
                {
                    case ESkillVfxType.Trap:
                        {
                            var to = battlePosition;
                            if (dto.masterType != EEntityType.Monster)
                            { // 施法者是玩家或者随从
                                to += skillVfxs.SkillVfxPositions[1].ToVector3();
                            }
                            // 陷阱位置随机
                            to.x += UnityEngine.Random.Range(-4, 5);
                            to.y += UnityEngine.Random.Range(-2, 2);
                            LoadTrap(dto, skillVfxs.SkillVfx, to);
                        }
                        break;
                    case ESkillVfxType.AOE:
                        {
                            if (skillVfxs.VfxFollowType == (int)EVfxFollowType.World)
                            { // 坐标修改为本次战斗的世界坐标
                                dto.from = battlePosition;
                            }
                            var aoeFrom = skillVfxs.SkillVfxPositions[0].ToVector3();
                            var aoeTo = skillVfxs.SkillVfxPositions[1].ToVector3();
                            if (dto.masterType == EEntityType.Monster)
                            { // 怪物在上，玩家在下
                                aoeFrom.y *= -1;
                                aoeTo.y *= -1;
                            }
                            aoeTo += dto.from;
                            dto.from += aoeFrom;
                            LoadAOEEntity(dto, skillVfxs.SkillVfx, aoeTo);
                        }
                        break;
                    case ESkillVfxType.AOENoMove:
                        {
                            var to = battlePosition;
                            to += skillVfxs.SkillVfxPositions[0].ToVector3();
                            dto.from = to;
                            LoadAOEEntity(dto, skillVfxs.SkillVfx, to);
                        }
                        break;
                    case ESkillVfxType.AOETarget:
                        {
                            var to = dto.from;
                            LoadAOEEntity(dto, skillVfxs.SkillVfx, to);
                        }
                        break;
                    default:
                        throw new NotImplementedException();
                }
            }
        }
        private void LoadTrap(GenSummonsDto dto, string vfxName, Vector3 tarPosition)
        {
            var loadAsync = Context.Asset.LoadEntity<TrapEntityView>(vfxName, Context.VM.BulletRoot);
            loadAsync.On(_ =>
            {
                var view = loadAsync.Result;
                if (view == null)
                    return;
                view.UID = UIDDefine.New();
                view.MasterId = dto.masterId;
                view.TableId = dto.tableId;
                view.Selector = _selector;
                view.Position = dto.from;
                _entityViewsMap.Add(view.UID, view);
                view.AI.Start(tarPosition, dto.targetType);
            });
        }
        private void LoadAOEEntity(GenSummonsDto dto, string vfxName, Vector3 tarPosition)
        {
            var loadAsync = Context.Asset.LoadEntity<AOEEntityView>(vfxName, Context.VM.BulletRoot);
            loadAsync.On(_ =>
            {
                var view = loadAsync.Result;
                if (view == null)
                    return;
                view.UID = UIDDefine.New();
                view.MasterId = dto.masterId;
                view.TableId = dto.tableId;
                view.Selector = _selector;
                view.Position = dto.from;
                _entityViewsMap.Add(view.UID, view);
                view.AI.Start(tarPosition, dto.targetType);
            });
        }
        #endregion
    }
}