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

namespace Cirno.Scripts.Components.FSM.Enemy;

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

    [Export]
    public EnemyStorageModule StorageModule { get; private set; }
    
    [Export]
    public GenericDamageReceiver DamageReceiver { get; private set; }
    
    [Export]
    private InputProvider _inputProvider;
    
    [Export]
    public PlayerCrosshairProvider CrosshairProvider { get; private set; }
    
    [Export] public Weapon EquippedWeapon { get; private set; }
    
    [Export] public StringName ControlEndAction { get; private set; } = "pause";

    [Export] public StringName ShootAction { get; private set; } = "shoot";

    private bool _isStrafing = false;
    
    public override void EnterState()
    {
        base.EnterState();
        
        GD.Print($"{StorageModule.Root.Name} Controlled");
        
        DamageReceiver.ChangeState(true);
        
        DamageReceiver.HealthProvider.ResourceDepleted += HealthProviderOnResourceDepleted;
        
        GameManager.Instance.CameraTargetObject(MainObject);
        GameManager.Instance.Player.SetState(PlayerState.Controlling);
        
        DamageReceiver.BulletGroup = BulletOwner.Player;

        _isStrafing = false;

        CrosshairProvider.Visible = true;
        // Show possession sprite

    }
    
    private void HealthProviderOnResourceDepleted()
    {
        ChangeState(EnemyState.Dead);
    }

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

        DamageReceiver.HealthProvider.ResourceDepleted -= HealthProviderOnResourceDepleted;
        DamageReceiver.ChangeState(false);
        
        GameManager.Instance.CameraTargetPlayer();
        GameManager.Instance.Player.SetState(PlayerState.Active);
        DamageReceiver.BulletGroup = BulletOwner.Enemy;
        CrosshairProvider.Visible = false;
        // Hide possession sprite
    }

    public override void PhysicsProcessState(double delta)
    {
        base.PhysicsProcessState(delta);
        
        if (_inputProvider.GetShootPressed())
        {
            Shoot();
        }
        
        if (Input.IsActionJustPressed(ControlEndAction))
        {
            // if (GameManager.Instance.ToggleControlMode() is GameState.Playing)
            // {
            //     ResumeControl();
            // }
            StateMachine.SetState(EnemyState.Idle);
        }
        
        HandlePhysics(delta);
        
        StorageModule.FacingDirection = MainObject.Velocity.SnapToCardinal().Normalized();
    }

    private void HandlePhysics(double delta)
    {
        StorageModule.MovementDirection = _inputProvider.GetMovementInput().Normalized();
        
        _isStrafing = _inputProvider.GetStrafePressed();
        
        var rightStickInput = _inputProvider.GetAimInput().Normalized();
        
        if (rightStickInput.Length() > 0.1f) // If the right stick is moved
        {
            StorageModule.AimingDirection = rightStickInput;
        }
        else if (StorageModule.MovementDirection != Vector2.Zero) // Fall back to movement direction
        {
            StorageModule.AimingDirection = StorageModule.MovementDirection;
        }
        
        // Update crosshair
        CrosshairProvider.UpdatePosition(StorageModule.AimingDirection);

        MainObject.Velocity = StorageModule.MovementDirection * StorageModule.MovementSpeed;
        
        MainObject.MoveAndSlide();

    }
    
    private void Shoot()
    {
        if (EquippedWeapon == null) return;

        var direction = StorageModule.AimingDirection;
        
        // Shoot at the player's last known position
        EquippedWeapon.ShootDirection = direction;
        //StorageModule.FacingDirection = direction;
        //StorageModule.FacingDirection = direction.SnapToCardinal().Normalized();
        
        EquippedWeapon.Shoot(BulletOwner.Player);
    }
    
    public override void ProcessState(double delta)
    {
        base.ProcessState(delta);
    }

}