using Sandbox;
using System;
namespace VeloX;

public abstract partial class VeloXBase
{
	[Feature( "Input" )] internal InputResolver Input { get; set; } = new();
	[Feature( "Input" )] public Connection Driver { get => Input.Driver; set => Input.Driver = value; }


	private bool IsDriverActive => Driver is not null;

	public Vector2 MouseDelta => IsDriverActive ? Input.MouseDelta : default;
	public Vector2 MouseWheel => IsDriverActive ? Input.MouseWheel : default;
	public Angles AnalogLook => IsDriverActive ? Input.AnalogLook : default;
	public Vector3 AnalogMove => IsDriverActive ? Input.AnalogMove : default;

	private float throttle;
	private float brakes;
	private float steerAngle;
	private float handbrake;

	public bool CanInputSwapping { get; set; } = true;
	public bool IsInputSwapped => CanInputSwapping && Transmission.Gear < 0;

	public bool IsShiftingDown { get; private set; }


	public bool IsShiftingUp { get; private set; }

	public float IsClutching { get; private set; }

	public float SwappedThrottle => IsInputSwapped ? Brakes : Throttle;
	public float SwappedBrakes => IsInputSwapped ? Throttle : Brakes;


	[Sync]
	public float VerticalInput
	{
		get => throttle - brakes;
		set
		{
			float clampedValue = Math.Clamp( value, -1, 1 );

			if ( value > 0 )
			{
				throttle = clampedValue;
				brakes = 0;
			}
			else
			{
				throttle = 0;
				brakes = -clampedValue;
			}
		}
	}

	/// <summary>
	///     Throttle axis.
	///     For combined throttle/brake input use 'VerticalInput' instead.
	/// </summary>
	[Sync( SyncFlags.Interpolate ), Range( 0, 1 ), Property, ReadOnly]
	public float Throttle
	{
		get => throttle;
		set => throttle = Math.Clamp( value, 0, 1 );
	}

	/// <summary>
	///     Brake axis.
	///     For combined throttle/brake input use 'VerticalInput' instead.
	/// </summary>
	[Range( 0, 1 ), Property, ReadOnly]
	public float Brakes
	{
		get => brakes;
		set => brakes = Math.Clamp( value, 0, 1 );
	}

	[Sync( SyncFlags.Interpolate ), Range( 0, 1 ), Property, ReadOnly]
	public float SteeringAngle
	{
		get => steerAngle;
		set => steerAngle = Math.Clamp( value, -1, 1 );
	}

	[Sync]
	public float Handbrake
	{
		get => handbrake;
		set => handbrake = Math.Clamp( value, 0, 1 );
	}


	public void ResetInput()
	{
		VerticalInput = 0;
		Handbrake = 0;

		SteeringAngle = 0;

		IsClutching = 0;

		IsShiftingUp = false;
		IsShiftingDown = false;
	}
	protected void UpdateInput()
	{
		VerticalInput = Input.AnalogMove.x;
		Handbrake = Input.Down( "Handbrake" ) ? 1 : 0;

		SteeringAngle = Input.AnalogMove.y;

		IsClutching = Input.Down( "Clutch" ) ? 1 : 0;

		IsShiftingUp = Input.Pressed( "Shift Up" );
		IsShiftingDown = Input.Pressed( "Shift Down" );

		if ( TotalSpeed < 150 && Driver is null )
			Handbrake = 1;

	}


	public bool Down( string action )
	{
		return IsDriverActive && Input.Down( action );
	}

	public bool Pressed( string action )
	{
		return IsDriverActive && Input.Pressed( action );
	}

	public bool Released( string action )
	{
		return IsDriverActive && Input.Released( action );
	}

	public void TriggerHaptics( float leftMotor, float rightMotor, float leftTrigger = 0f, float rightTrigger = 0f, int duration = 500 )
	{
		if ( IsDriverActive )
		{
			Input.TriggerHaptics( leftMotor, rightMotor, leftTrigger, rightTrigger, duration );
		}
	}
	public void TriggerHaptics( HapticEffect effect, float lengthScale = 1, float frequencyScale = 1, float amplitudeScale = 1 )
	{
		if ( IsDriverActive )
		{
			Input.TriggerHaptics( effect, lengthScale, frequencyScale, amplitudeScale );
		}
	}

	public void StopAllHaptics()
	{
		if ( IsDriverActive )
			Input.StopAllHaptics();
	}

}
