using System.Linq;
using AceFieldNewHorizon.Scripts.Entities;
using Godot;

namespace AceFieldNewHorizon.Scripts.Tiles;

public partial class TurretTile : BaseTile
{
    [Export] public PackedScene BulletScene;
    
    [Export] public float RotationSpeed = 2.0f; // Radians per second
    [Export] public float AttackRange = 300.0f;
    [Export] public float AttackCooldown = 0.5f;
    [Export] public int Damage = 10;
    [Export] public float BulletSpeed = 400.0f;
    [Export] public NodePath BarrelTipPath;
    
    private Node2D _spriteBarrel;
    private Node2D _barrelTip;
    private float _attackTimer = 0;
    private bool _hasTarget = false;

    public override void _Ready()
    {
        base._Ready();

        _spriteBarrel = GetNodeOrNull<Node2D>("Barrel");
        _barrelTip = GetNodeOrNull<Node2D>(BarrelTipPath);
        
        if (_barrelTip == null && _spriteBarrel != null)
        {
            // If no barrel tip is specified, use the end of the barrel sprite
            _barrelTip = _spriteBarrel.GetNodeOrNull<Node2D>("BarrelTip");
        }
    }

    public override void SetGhostMode(bool canPlace)
    {
        base.SetGhostMode(canPlace);

        if (_spriteBarrel != null)
            _spriteBarrel.Modulate = canPlace
                ? new Color(0, 1, 0, 0.5f)
                : new Color(1, 0, 0, 0.5f);
    }

    public override void FinalizePlacement()
    {
        base.FinalizePlacement();

        if (_spriteBarrel != null)
            _spriteBarrel.Modulate = Colors.White;
    }

    public override void _Process(double delta)
    {
        if (!IsConstructed) return;

        // Update attack cooldown
        if (_attackTimer > 0)
        {
            _attackTimer -= (float)delta;
        }

        // Find the nearest enemy
        var enemies = GetTree().GetNodesInGroup(Enemy.EnemyGroupName)
            .OfType<Enemy>()
            .Where(e => e.GlobalPosition.DistanceTo(GlobalPosition) <= AttackRange)
            .OrderBy(e => e.GlobalPosition.DistanceTo(GlobalPosition))
            .ToList();

        if (enemies.Count > 0)
        {
            var nearestEnemy = enemies[0];
            _hasTarget = true;
            
            // Calculate target angle
            var direction = (nearestEnemy.GlobalPosition - _barrelTip.GlobalPosition).Normalized();
            var targetAngle = direction.Angle() + 90f;

            // Smoothly rotate towards target
            _spriteBarrel.Rotation = Mathf.LerpAngle(_spriteBarrel.Rotation, targetAngle, (float)delta * RotationSpeed);

            // Check if we're facing the target and can attack
            if (Mathf.Abs(Mathf.Wrap(targetAngle - _spriteBarrel.Rotation, -Mathf.Pi, Mathf.Pi)) < 0.1f)
                TryAttack(nearestEnemy.GlobalPosition);
        }
        else
        {
            _hasTarget = false;
        }
    }

    private void TryAttack(Vector2 targetPosition)
    {
        if (_attackTimer <= 0 && BulletScene != null && _barrelTip != null)
        {
            // Create bullet instance
            var bullet = BulletScene.Instantiate<Bullet>();
            
            // Calculate direction and rotation
            var direction = (targetPosition - _barrelTip.GlobalPosition).Normalized();
            var bulletRotation = direction.Angle();
            
            // Set bullet position and rotation
            GetTree().CurrentScene.AddChild(bullet);
            bullet.GlobalPosition = _barrelTip.GlobalPosition;
            bullet.Rotation = bulletRotation; // Use the calculated rotation
            
            // Initialize bullet with direction and damage
            bullet.Initialize(
                direction, 
                bullet.GlobalPosition, 
                bulletRotation, // Pass the calculated rotation
                1 // Pass the turret's collision layer to ignore
            );
            bullet.Damage = Damage;
            bullet.Speed = BulletSpeed;
            bullet.MaxDistance = AttackRange * 1.5f; // Bullets can travel slightly further than attack range
            
            // Reset attack cooldown
            _attackTimer = AttackCooldown;
            
            GD.Print("[Turret] Turret firing!");
        }
    }
}