using System.Linq;
using Cirno.Scripts.Enums;
using Cirno.Scripts.Resources;
using Godot;
using Godot.Collections;

namespace Cirno.Scripts.Components.Actors;

public partial class GenericDamageReceiver : Area2D, IHittable
{
    [Export] public ActorResourceProvider HealthProvider { get; private set; }

    [Export] public bool Invulnerable { get; private set; } = false;

    [Export] public BulletOwner BulletGroup { get; set; } = BulletOwner.None;

    [Export] public PackedScene Debris { get; set; }
    
    [Export] public Array<DamageResistance> DamageResistances { get; set; } = [];

    [Export] public bool DeleteParentOnDeath { get; private set; } = true;

    [Signal]
    public delegate void ShieldHitEventHandler();
    
    [Signal] public delegate void BulletHitEventHandler(Bullet bullet, Vector2 position, Vector2 direction);
    
    //[Signal] public delegate void DeathEventHandler();
    
    private Node2D _parent;
    
    public bool Enabled { get; private set; } = true;
    
    public override void _Ready()
    {
        _parent = GetParent<Node2D>();
        HealthProvider.FillResource();
        HealthProvider.ResourceDepleted += OnDeath;
    }

    public void ChangeState(bool enabled)
    {
        Enabled = enabled;
    }
    
    private void _on_damage_hitbox_area_entered(Area2D area)
    {
        if (!Enabled) return;
        if (area is not Bullet bullet) return;
        if (Invulnerable)
        {
            EmitSignalShieldHit();
            return;
        };

        if (BulletGroup is BulletOwner.None)
        {
            this.Hit(bullet.Damage, bullet.DamageType);
            
            EmitSignalBulletHit(bullet, area.GlobalPosition, (this.GlobalPosition - area.GlobalPosition).Normalized());
            
            bullet.RequestCollisionDestruction();
            return;
        }

        if (bullet.BulletInfo.Owner == BulletGroup) return; 
        
        this.Hit(bullet.Damage, bullet.DamageType);
        
        EmitSignalBulletHit(bullet, area.GlobalPosition, (this.GlobalPosition - area.GlobalPosition).Normalized());
        
        bullet.RequestCollisionDestruction();
    }
    
    public void Hit(float damage, DamageType damageType = DamageType.Neutral)
    {
        if (!Enabled) return;
        if (Invulnerable) return;
        
        // Change value based on difficulty
        float difficultyReducedDmg = damage * GlobalState.Instance.SessionSettings.DifficultyDamageMultiplier;

        var dmg = DamageResistances.Aggregate(difficultyReducedDmg, (current, resistance) => current * resistance.CalculateDamage(current, damageType));

        HealthProvider.CurrentResource -= dmg;
    }
    
    private void OnDeath()
    {
        if (Debris is not null)
        {
            _parent.CreateSibling<Node2D>(Debris);
        }
        
        // Not needed because the health provider is accessible
        //EmitSignal(SignalName.Death);
        
        if (DeleteParentOnDeath)
        {
            _parent.QueueFree();
        }
    }
}