using System;
using System.Linq;
using WingsEmu.DTOs.BCards;
using WingsEmu.Game._enum;
using WingsEmu.Game.Buffs;
using WingsEmu.Game.Characters;
using WingsEmu.Game.Entities;
using WingsEmu.Game.Extensions;
using WingsEmu.Game.Helpers.Damages;
using WingsEmu.Game.Skills;
using WingsEmu.Packets.Enums;
using WingsEmu.Packets.ServerPackets.Battle;

namespace WingsEmu.Game.Battle;

public class SkillExecutor : ISkillExecutor
{
    private readonly IBCardEffectHandlerContainer _bCardEffectHandlerContainer;

    public SkillExecutor(IBCardEffectHandlerContainer bCardEffectHandlerContainer) => _bCardEffectHandlerContainer = bCardEffectHandlerContainer;

    public void ExecuteDamageSkill(IBattleEntity caster, IBattleEntity target, SkillCast skill, Position positionBeforeDash = default)
    {
        if (IsDestroyerBomb(caster, skill))
        {
            return;
        }

        caster.BroadcastCastPacket(target, skill.Skill);
        var hitProcessable = new HitProcessable(caster, target, skill, positionBeforeDash);
        caster.MapInstance.AddCastHitRequest(hitProcessable);
    }


    public void ExecuteDamageZoneHitSkill(IBattleEntity caster, SkillCast skill, Position position)
    {
        caster.BroadcastCastNonTarget(skill.Skill);
        var hitProcessable = new HitProcessable(caster, null, skill, position);
        caster.MapInstance.AddCastHitRequest(hitProcessable);
    }

    public void ExecuteBuffZoneHitSkill(IBattleEntity caster, SkillCast skill, Position position)
    {
        caster.BroadcastCastNonTarget(skill.Skill);
        var buffProcessable = new BuffProcessable(caster, null, skill, position);
        caster.MapInstance.AddCastBuffRequest(buffProcessable);
    }

    public void ExecuteDebuffZoneHitSkill(IBattleEntity caster, SkillCast skill, Position position)
    {
        caster.BroadcastCastNonTarget(skill.Skill);
        var buffProcessable = new BuffProcessable(caster, null, skill, position);
        caster.MapInstance.AddCastBuffRequest(buffProcessable);
    }

    public void ExecuteBuffSkill(IBattleEntity caster, IBattleEntity target, SkillCast skill)
    {
        SkillInfo skillInfo = skill.Skill;
        bool isTeleport = skillInfo.Vnum == (short)SkillsVnums.ARCH_TELEPORT;

        caster.BroadcastCastPacket(target, skillInfo);

        if (isTeleport)
        {
            caster.BroadcastSuPacket(caster, skillInfo, 0, SuPacketHitMode.NoDamageSuccess);
            foreach (BCardDTO x in skillInfo.BCards)
            {
                _bCardEffectHandlerContainer.Execute(caster, caster, x, skillInfo);
            }

            return;
        }

        caster.MapInstance.AddCastBuffRequest(new BuffProcessable(caster, target, skill));
    }

    public void ExecuteDebuffSkill(IBattleEntity caster, IBattleEntity target, SkillCast skill)
    {
        caster.BroadcastCastPacket(target, skill.Skill);
        caster.MapInstance.AddCastBuffRequest(new BuffProcessable(caster, target, skill));
    }

    private bool IsDestroyerBomb(IBattleEntity caster, SkillCast skill)
    {
        if (skill.Skill.Vnum != (short)SkillsVnums.BOMB)
        {
            return false;
        }

        if (caster is not IPlayerEntity character)
        {
            return false;
        }

        if (!character.SkillComponent.BombEntityId.HasValue)
        {
            return false;
        }

        long characterId = character.Id;
        IMonsterEntity bomb = character.MapInstance.GetAliveMonsters(x => x.Id == character.SkillComponent.BombEntityId
            && x.SummonerId == characterId && x.SummonerType == VisualType.Player && x.MonsterVNum == (short)MonsterVnum.BOMB).FirstOrDefault();
        if (bomb == null)
        {
            character.SkillComponent.BombEntityId = null;
            return false;
        }

        IBattleEntitySkill bombSkill = bomb.Skills.FirstOrDefault();
        if (bombSkill == null)
        {
            character.SkillComponent.BombEntityId = null;
            return false;
        }

        character.CancelCastingSkill();
        SkillInfo fakeBombSkill = character.GetFakeBombSkill();
        fakeBombSkill.Cooldown = (short)(skill.Skill.Cooldown == 0 ? 0 : fakeBombSkill.Cooldown);
        character.Session.SendSkillCooldownResetAfter(fakeBombSkill.CastId, fakeBombSkill.Cooldown);

        bomb.EmitEvent(new BattleExecuteSkillEvent(bomb, bomb, bombSkill.Skill.GetInfo(), DateTime.UtcNow));
        character.SetSkillCooldown(fakeBombSkill);
        character.SkillComponent.BombEntityId = null;
        return true;
    }
}