using FL.Nodes.GameMain;
using UnityEngine;
using XGame.Database;
using XGame.Framework.Components;

namespace FL.Battle.Components
{
    public interface ICombatContext
    {
        IEntity Entity { get; }
        ITargetSelector Selector { get; }
        Vector3 Position { get; }
        StatesComponent States { get; }
        BuffsComponent Buffs { get; }
        SkillComponent Skill { get; }
        /// <summary>
        /// 铭文组件
        /// 可能为空
        /// </summary>
        EpigraphicsComponent Epigraphics { get; }
    }
    public class CombatComponent : Component<ICombatContext>, ICombatCalculation
    {
        protected override void OnDispose()
        {
        }
        /// <summary>
        /// 计算血量
        /// 正数表示加血
        /// 负数表示扣血
        /// </summary>
        /// <param name="damage"></param>
        /// <returns></returns>
        private int CalculateHP(int damage)
        {
            var remainDamage = Context.Buffs.CalculateShieldAbsorb(damage);
            if (remainDamage == 0)
            { // 全部被护盾吸收
                return damage;
            }
            // 吸收值
            var absorption = damage - remainDamage;

            var attrs = Context.Entity.Attr;
            var lastHp = attrs.CurrentHp;
            var nextHp = lastHp + remainDamage;
            if (nextHp > attrs.HpLimit)
            {
                nextHp = attrs.HpLimit;
            }
            else if (nextHp < 0)
            {
                nextHp = 0;
            }
            attrs.CurrentHp = nextHp;
            if (nextHp == 0)
            {
                Context.States.AddState(EEntityState.Dead);
            }
            var result = (int)(nextHp - lastHp);
            // 返回扣血和护盾吸收的总和
            return result + absorption;

        }

        private void AddSkillBuff(SkillTable skill, ITarget attacker, int damage)
        {
            if (skill.BuffTie.Length != 2)
                return;
            var probability = skill.BuffTie[0];
            var buffId = skill.BuffTie[1];
            if (TryGetTrigger(BuffTableRepo.GetTargetType(buffId), attacker, out var trigger))
            {
                trigger?.Buffs.TryAddBuff(buffId, probability, 1, null, damage);
            }
            else
            {
                Context.Buffs.TryAddBuff(buffId, probability, 1, attacker?.Calculation, damage);
            }
        }
        /// <summary>
        /// 根据技能/Buff的目标类型确定触发目标
        /// </summary>
        /// <param name="targetType"></param>
        /// <param name="attacker"></param>
        /// <returns></returns>
        private ICombatCalculation GetTrigger(ESkillTargetType targetType, ICombatCalculation attacker)
        {
            if (TableUtils.IsContain((uint)targetType, ESkillTargetType.Attacker))
            {
                return attacker;
            }
            if (TableUtils.IsContain((uint)targetType, ESkillTargetType.Player))
            {
                return Context.Selector.GetPlayer()?.Calculation;
            }
            return this;
        }
        private bool TryGetTrigger(ESkillTargetType targetType, ITarget attacker, out ITarget trigger)
        {
            if (TableUtils.IsContain((uint)targetType, ESkillTargetType.Attacker))
            {
                trigger = attacker;
                return true;
            }
            if (TableUtils.IsContain((uint)targetType, ESkillTargetType.Player))
            {
                trigger = Context.Selector.GetPlayer();
                return true;
            }
            trigger = null;
            return false;
        }
        #region 被动技能
        //private void TickAttackerPassiveSkill(SkillTable skill, ICombatCalculation target)
        //{
        //    Context.Skill.TryTickPassiveSkills((passiveSkill) =>
        //    {
        //        return true;
        //    });
        //}
        #endregion

        #region 接口实现
        void ICombatCalculation.Damage(int damage, long attackerId, SkillTable skill)
        {
            if (Context.Entity.IsDead)
            { // 已经死亡
                return;
            }
            ITarget attacker = null;
            if (damage != 0)
            { // damage为零时不计算
                var damageAdd = 0;
                if (attackerId != Context.Entity.EntityId)
                { // 攻击者和受击者是同一个目标时不计算加成
                    attacker = Context.Selector.GetTarget(attackerId);
                    if (attacker != null && !attacker.IsDead)
                    {
                        damageAdd += attacker.Buffs.GetDamageAdd(skill.Element, Context.Entity, Context.Buffs);
                    }
                }
                damageAdd += Context.Buffs.GetDamageAdd(skill.Element, Context.Entity, Context.Buffs);
                var realDamage = Mathf.CeilToInt(damage * (1 + damageAdd.ToRealFloat()));
                damage = CalculateHP(realDamage);
                EventSingle.Instance.Notify(EventDefine.GameMainMapHpAdd, new HpAddDto()
                {
                    entityId = Context.Entity.EntityId,
                    position = Context.Position,
                    hpValue = damage,
                    elementType = skill.Element,
                });
                //攻击者触发铭文
                attacker?.Calculation.TickEpigraph(Context.Entity.EntityId, skill.Element, realDamage);
                // 受击目标的buff触发
                Context.Buffs.TickBuffOrSkill(damage, skill.Element, attacker?.Calculation);
            }
            //TODO 攻击者的buff触发
            AddSkillBuff(skill, attacker, damage);
            //TODO  受击者的被动技能
            //TODO  攻击者的被动技能
            //if (attacker != null && (attacker.Calculation is CombatComponent atkCalculation))
            //{
            //    atkCalculation.TickAttackerPassiveSkill(skill, this);
            //}
        }
        void ICombatCalculation.Damage(int damage, EElementType elementType)
        {
            if (Context.Entity.IsDead)
            { // 已经死亡
                return;
            }
            damage = CalculateHP(damage);
            if (damage == 0)
                return;
            EventSingle.Instance.Notify(EventDefine.GameMainMapHpAdd, new HpAddDto()
            {
                entityId = Context.Entity.EntityId,
                position = Context.Position,
                hpValue = damage,
                elementType = elementType,
            });
        }
        ICombatCalculation ICombatCalculation.GetSkillTrigger(long skillId, ICombatCalculation attacker)
        {
            return GetTrigger(SkillTableRepo.GetTargetType(skillId), attacker);
        }
        ICombatCalculation ICombatCalculation.GetBuffTrigger(long buffId, ICombatCalculation attacker)
        {
            return GetTrigger(BuffTableRepo.GetTargetType(buffId), attacker);
        }
        void ICombatCalculation.TickSkill(long skillId, long targetId, int probability)
        {
            // TODO
            Context.Skill.TryTickSkill((int)skillId, targetId, probability);
        }
        void ICombatCalculation.TickBuff(long buffId, int probability, int addLayer, int damage)
        {
            Context.Buffs.TryAddBuff(buffId, probability, addLayer, null, damage);
        }

        void ICombatCalculation.TickEpigraph(long targetId, EElementType skillElementType, int damage)
        {
            Context.Epigraphics?.TryTickIceToPoison(targetId, skillElementType, damage);
        }
        #endregion
    }
}
