using Cirno.Scripts.Components.Actors;
using Cirno.Scripts.Enums;
using Cirno.Scripts.Utils;
using Godot;

namespace Cirno.Scripts.Components.FSM.Enemy.Turret;

public partial class TurretShooting : EnemyStateBase
{
    public override EnemyState StateId => EnemyState.Shooting;
    
    [Export]
    public EnemyStorageModule StorageModule { get; private set; }
    
    [Export]
    public PlayerDetectionModule PlayerDetection { get; private set; }
    
    [Export]
    public GenericDamageReceiver DamageReceiver { get; private set; }
    
    [Export] public Weapon EquippedWeapon;
    
    private bool _isPlayerInRange = false;
    
    private double _responseTimer = 0;
    
    public override void EnterState()
    {
        base.EnterState();
        
        PlayerDetection.PlayerOutOfRange += PlayerDetectionOnPlayerOutOfRange;

        DamageReceiver.ChangeState(true);
        
        DamageReceiver.HealthProvider.ResourceDepleted += HealthProviderOnResourceDepleted;

        EquippedWeapon.WeaponData = StorageModule.Root.EnemyResource.Weapon;
        
        _responseTimer = 0;
    }
    
    private void HealthProviderOnResourceDepleted()
    {
        ChangeState(EnemyState.Dead);
    }
    
    private void PlayerDetectionOnPlayerOutOfRange()
    {
        StateMachine.SetState(EnemyState.Alert);
    }
    
    public override void ExitState()
    {
        base.ExitState();
        
        PlayerDetection.PlayerOutOfRange -= PlayerDetectionOnPlayerOutOfRange;
        
        DamageReceiver.HealthProvider.ResourceDepleted -= HealthProviderOnResourceDepleted;
        
        DamageReceiver.ChangeState(false);
        
    }

    public override void PhysicsProcessState(double delta)
    {
        base.PhysicsProcessState(delta);
        
        if (PlayerDetection.IsPlayerInRange(StorageModule.Root.EnemyResource.ViewRange) && PlayerDetection.IsPlayerInSight())
        {
            // SHOOT
            Shoot();
        }
        else
        {
            StateMachine.SetState(EnemyState.Alert);
            return;
        }
        
    }
    
    private Vector2 GetShootDirection()
    {
        if (StorageModule.EnemyData.PredictPlayer && PlayerDetection.LastKnowPlayerVelocity.HasValue)
        {
            var predictedDirection = MathFunctions.PredictInterceptPosition(MainObject.GlobalPosition,
                PlayerDetection.LastKnownPlayerPosition.Value, PlayerDetection.LastKnowPlayerVelocity.Value,
                EquippedWeapon.WeaponData.BulletData.BulletSpeed);
            if (predictedDirection.HasValue) return (predictedDirection.Value - MainObject.GlobalPosition).Normalized();
            
        }
        
        return ( PlayerDetection.LastKnownPlayerPosition.Value - MainObject.GlobalPosition).Normalized();
    }
    
    private void Shoot()
    {
        if (EquippedWeapon == null) return;
        if (!PlayerDetection.LastKnownPlayerPosition.HasValue) return;
        
        var direction = GetShootDirection();
        
        // Shoot at the player's last known position
        EquippedWeapon.ShootDirection = direction;
        //StorageModule.FacingDirection = direction;
        StorageModule.FacingDirection = direction;
        StorageModule.AimingDirection = direction;
        
        EquippedWeapon.Shoot();
    }
}