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

namespace Cirno.Scripts.Components.FSM.Enemy;

public partial class Alert : EnemyStateBase
{
    public override EnemyState StateId => EnemyState.Alert;

    [Export]
    public EnemyStorageModule StorageModule { get; private set; }
    
    [Export]
    public PlayerDetectionModule PlayerDetection { get; private set; }
    
    [Export]
    public GenericDamageReceiver DamageReceiver { get; private set; }
    
    [Export]
    public NavigationMovementModule NavigationModule { get; private set; }
    
    private bool _isPlayerInRange = false;
    
    public override void EnterState()
    {
        base.EnterState();
        NavigationModule.Init(MainObject);
        
        PlayerDetection.SetRange(StorageModule.Root.EnemyResource.PlayerDetectionRange);
        
        //_isPlayerInRange = PlayerDetection.IsPlayerInRange(StorageModule.Root.EnemyResource.ViewRange);
        //GD.Print($"Player In Range: {_isPlayerInRange}");
        
        PlayerDetection.PlayerInRange += PlayerDetectionOnPlayerInRange;
        
        PlayerDetection.PlayerOutOfRange += PlayerDetectionOnPlayerOutOfRange;

        DamageReceiver.ChangeState(true);
        
        DamageReceiver.HealthProvider.ResourceDepleted += HealthProviderOnResourceDepleted;
    }
    
    private void HealthProviderOnResourceDepleted()
    {
        ChangeState(EnemyState.Dead);
    }

    private void PlayerDetectionOnPlayerOutOfRange()
    {
        _isPlayerInRange = false;
    }

    public override void ExitState()
    {
        base.ExitState();
        PlayerDetection.PlayerInRange -= PlayerDetectionOnPlayerInRange;
        
        PlayerDetection.PlayerOutOfRange -= PlayerDetectionOnPlayerOutOfRange;
        
        DamageReceiver.HealthProvider.ResourceDepleted -= HealthProviderOnResourceDepleted;
        DamageReceiver.ChangeState(false);
        NavigationModule.SetTarget(null);   
    }

    private void PlayerDetectionOnPlayerInRange()
    {
        //_isPlayerInRange = true;
    }

    public override void PhysicsProcessState(double delta)
    {
        base.PhysicsProcessState(delta);
        if (PlayerDetection.IsPlayerInRange(StorageModule.Root.EnemyResource.ViewRange) && PlayerDetection.IsPlayerInSight())
        {
            StateMachine.SetState(EnemyState.Shooting);
            return;
        }
        
        // if player is outside disengage range, change to idle (later on, search)
        if (MainObject.GlobalPosition.DistanceTo(GameManager.Instance.PlayerPosition.Value) >=
            StorageModule.Root.EnemyResource.PlayerDisengageRange)
        {
            StateMachine.SetState(EnemyState.Idle);
            return;
        }
        
        // Move towards last known position
        if (PlayerDetection.LastKnownPlayerPosition.HasValue)
        {
            MoveTowardsPosition(PlayerDetection.LastKnownPlayerPosition.Value);
        }
            
        NavigationModule.Move(StorageModule.EnemyData.MovementSpeed);

        StorageModule.FacingDirection = MainObject.Velocity.SnapToCardinal().Normalized();
        StorageModule.AimingDirection = StorageModule.FacingDirection;
    }

    private void MoveTowardsPosition(Vector2 position)
    {
        NavigationModule.SetTarget(position);
    }

    public override void ProcessState(double delta)
    {
        base.ProcessState(delta);
    }
}