using Godot;
using System;
using System.Diagnostics;
using System.Linq;
using Cirno.Scripts;
using Cirno.Scripts.Controllers;
using Cirno.Scripts.Resources;
using Godot.Collections;

public partial class Barrel : Area2D, IDestructible
{
	[Export] public bool Indestructible { get; private set; }
	[Export] public float Health = 1f;

	[Export] public float ExplosionRadius = 1;

	[Export] public float ExplosionDamage = 1;

	[Export] public PackedScene DebrisScene { get; set; }
	
	[Export] public PackedScene ExplosionParticles { get; set; }
	[Export] public BulletResource ExplosionData { get; set; }

	[Export] public BulletOwner BulletGroup { get; set; } = BulletOwner.None;
	[Export] public Array<DamageResistance> DamageResistances { get; set; } = [];

	[ExportCategory("On Death Activation")]
	[Export]
	public ActivationType ActivationType { get; private set; } = ActivationType.Toggle;
	[Export]
	public Node2D Target { get; private set;}
	
	
	[Signal]
	public delegate void ExplodedEventHandler();
	
	private GameManager _gameManager;

	private float _currentHealth = 0f;

	private bool _isDestroyed = false;

	// Called when the node enters the scene tree for the first time.
	public override void _Ready()
	{
		_gameManager = this.GetGameManager();
		_currentHealth = Health;
	}

	// Called every frame. 'delta' is the elapsed time since the previous frame.
	public override void _Process(double delta)
	{
	}

	private void Explode()
	{
		//ApplyExplosionDamage();
		EmitSignal(SignalName.Exploded, this, _currentHealth);
		ActivateOnDeath();
		CreateExplosion();
		CreateParticles();
		CreateDebris();
		
		QueueFree();
		
		GameManager.Instance.RebakeNavigation();
		//GameManager.Instance.RecalculateTilemap(this.GlobalPosition);
	}

	private void ActivateOnDeath()
	{
		if (Target is IActivable node)
		{
			node.Activate(ActivationType);
		}
	}

	private void CreateExplosion() 
	{
		if (ExplosionData == null) return;


		var explosion = PoolingManager.Instance.SpawnBullet(ExplosionData);
		explosion.GlobalPosition = this.GlobalPosition;
		
		//var explosion = this.CreateSibling<Bullet>(ExplosionData.BulletScene);
		explosion.Speed = 0;
		
		explosion.Initialize(ExplosionData.MakeBullet(this.GlobalPosition), _gameManager);
	}

	private void ApplyExplosionDamage()
    {
        var spaceState = GetWorld2D().DirectSpaceState;
        var query = new PhysicsShapeQueryParameters2D();
        var shape = new CircleShape2D { Radius = ExplosionRadius };
        
        query.SetShape(shape);
        query.Transform = new Transform2D(0, GlobalPosition);
        query.CollideWithBodies = false;
        query.CollideWithAreas = true;
		//query.CollisionMask = ;

        var results = spaceState.IntersectShape(query);
		
		GD.Print($"Shapes in range: {results.Count}");

        foreach (var result in results)
        {
            if (result.TryGetValue("collider", out var colliderObj))
            {

  				var collider = colliderObj.As<Node2D>();


                if (collider.GetParent<Area2D>() is IDestructible destructible)
                {
					GD.Print($"HITTING {collider.Name}");
                    destructible.Hit(ExplosionDamage);
                }
				else {
					GD.Print($"Collider {collider.Name} was not idestructible");
				}
            }
        }
    }

	private void CreateDebris()
	{
		if (DebrisScene == null) return;
		this.CreateSibling<Barrel>(DebrisScene);
	}

	private void CreateParticles()
	{
		if (ExplosionParticles == null) {
			return;
		}
		var particle = this.CreateSibling<GpuParticles2D>(ExplosionParticles);
		if (particle == null) return;

		particle.Emitting = true;
		
	}


	public void Hit(float damage, DamageType damageType = DamageType.Neutral)
	{
		if (_isDestroyed || Indestructible) return;
		
		var dmg = DamageResistances.Aggregate(damage, (current, resistance) => current * resistance.CalculateDamage(current, damageType));
		
		_currentHealth -= dmg;
		if (_currentHealth > 0) return;
		_isDestroyed = true;
		Explode();
	}

	public bool IsDestroyed()
	{
		return _isDestroyed;
	}
}
