using System;
using System.Threading.Tasks;
using Godot;

namespace Cirno.Scripts.Components.Actors;

public partial class KeyboardInputProvider : InputProvider
{
    [ExportCategory("Movement")]
    [Export]
    public StringName LeftAxisName { get; private set; } = "left";
    [Export]
    public StringName RightAxisName { get; private set; } = "right";
    [Export]
    public StringName UpAxisName { get; private set; } = "up";
    [Export]
    public StringName DownAxisName { get; private set; } = "down";

    [ExportCategory("Aiming")]
    [Export]
    public StringName LeftAimName { get; private set; } = "aim_left";
    [Export]
    public StringName RightAimName { get; private set; } = "aim_right";
    [Export]
    public StringName UpAimName { get; private set; } = "aim_up";
    [Export]
    public StringName DownAimName { get; private set; } = "aim_down";

    [ExportCategory("Action Names")]
    [Export] private StringName _shootActionName = "shoot";
    [Export] private StringName _useActionName = "Use";
    [Export] private StringName _scanActionName = "scan";
    [Export] private StringName _strafeActionName = "strafe";
    [Export] private StringName _nextWeaponActionName = "next_weapon";
    [Export] private StringName _previousWeaponActionName = "previous_weapon";
    [Export] private StringName _inventoryActionName = "inventory";
    [Export] private StringName _pauseActionName = "pause";
    [Export] private StringName _freezeActionName = "Freeze";
    [Export] private StringName _reloadActionName = "Reload";

    private enum AimInputMethod { RightStick, Mouse }
    private AimInputMethod _lastUsedInput = AimInputMethod.RightStick;

    public override void _Ready()
    {
        
        CallDeferred(MethodName.DelayedRegisterGameManager);
    }

    private void DelayedRegisterGameManager()
    {
        if (GameManager.Instance is null)
        {
            GD.Print("No GameManager found for keyboard inputprovider");
            return;
        }
        GameManager.Instance.GameStateChange += InstanceOnGameStateChange;
        _enabled = true;
    }

    private bool _enabled = false;

    private void InstanceOnGameStateChange(GameState state)
    {
        if (state is not GameState.Playing) return;
        
        _enabled = false;

        _ = DelayResume();
    }

    private async Task DelayResume()
    {
        //await ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame);
        await Task.Delay(200);
        _enabled = true;
    }
    
    public override Vector2 GetMovementInput()
    {
        return Input.GetVector(LeftAxisName, RightAxisName, UpAxisName, DownAxisName);
    }

    public override Vector2 GetAimInput()
    {
        Vector2 rightStickInput = GetRightStickInput();
        Vector2 mouseInput = GetMouseAimInput();

        // Determine which input method to use
        if (rightStickInput != Vector2.Zero)
        {
            _lastUsedInput = AimInputMethod.RightStick;
        }
        else if (mouseInput != Vector2.Zero)
        {
            _lastUsedInput = AimInputMethod.Mouse;
        }

        return _lastUsedInput == AimInputMethod.RightStick ? rightStickInput : mouseInput;
    }
    
    private Vector2 GetRightStickInput()
    {
        return new Vector2(
            Input.GetAxis(LeftAimName,RightAimName), 
            Input.GetAxis(UpAimName, DownAimName)
        );
    }
    
    private Vector2 GetMouseAimInput()
    {
        //Camera2D camera = GetViewport().GetCamera2D();
        //if (camera == null) return Vector2.Zero; // Ensure there's a valid camera
        
        //Vector2 mouseScreenPos = GetViewport().get_local_mouse_position();
        if (GameManager.Instance is null) return Vector2.Zero;
        
        Vector2 mouseWorldPos = DisplayServer.MouseGetPosition();// GameManager.Instance.GetGlobalMousePosition();
    
        return mouseWorldPos - GameManager.Instance.PlayerPosition.Value; // Get direction vector
    }

    public override bool GetActionJustPressed(string action)
    {
        return Input.IsActionJustPressed(action);
    }

    public override bool GetActionPressed(string action)
    {
        return Input.IsActionPressed(action);
    }

    public override bool GetInventoryJustPressed()
    {
        return GetActionJustPressed(_inventoryActionName);
    }
    
    public override bool GetShootPressed()
    {
        return _enabled && GetActionPressed(_shootActionName);
    }
    
    public override bool GetShootJustPressed()
    {
        return GetActionJustPressed(_shootActionName);
    }

    public override bool GetUseJustPressed()
    {
        return GetActionJustPressed(_useActionName);
    }
    public override bool GetScanJustPressed()
    {
        return GetActionJustPressed(_scanActionName);
    }

    public override bool GetStrafePressed()
    {
        return GetActionPressed(_strafeActionName);
    }

    public override bool GetWeaponNextJustPressed()
    {
        return GetActionJustPressed(_nextWeaponActionName);
    }

    public override bool GetWeaponPreviousJustPressed()
    {
        return GetActionJustPressed(_previousWeaponActionName);
    }

    public override bool GetPauseJustPressed()
    {
        return GetActionJustPressed(_pauseActionName);
    }
    
    public override bool GetFreezeJustPressed()
    {
        return GetActionJustPressed(_freezeActionName);
    }
    
    public override bool GetFreezePressed()
    {
        return GetActionPressed(_freezeActionName);
    }
    
    public override bool GetReloadJustPressed()
    {
        return GetActionJustPressed(_reloadActionName);
    }
    
    public override bool GetReloadPressed()
    {
        return GetActionPressed(_reloadActionName);
    }

}