using Godot;
using Sfs3.Client.Entities.Data;

/**
 * Script attached to the main node in the Starship scene.
 *
 * The starship of each player in the game; the animation frames are those of the
 * model selected by the player (see the resources in the images/ships folder).
 */
public partial class Starship : GameItem
{
	private const string ANIM_SHIP = "ship";

	private const string FRAMES_PATH = "res://images/ships/";

	[Export]
	public Node2D main;
	[Export]
	public Sprite2D radar;
	[Export]
	public ProgressBar shieldBar;
	[Export]
	public Label usernameLabel;

	public int userId;

	private ISFSObject settings;
	private bool _isMine;
	private bool _doThrust;
	private int _thrusterValue;
	private int _rotatingDir;   // Set to +1 if ship is currently rotating counterclockwise, -1 if clockwise and 0 if not rotating
	private int _shield;
	private float _rotation;

	//----------------------------------------------------------
	// Properties
	//----------------------------------------------------------
	#region
	public string username
	{
		set => usernameLabel.Text = value;

		get => usernameLabel.Text;
	}

	/**
	 * Thruster state: 0 is no flame, 1 the small flame shown while the server is being notified
	 * of a thrust activation or deactivation, 2 the full flame of an active thruster.
	 */
	public int thrusterValue
	{
		set
		{
			_thrusterValue = value;
			sprite.Frame = value;
		}

		get => _thrusterValue;
	}

	public bool doThrust
	{
		set
		{
			_doThrust = value;
			thrusterValue = value ? 2 : 0;
		}

		get => _doThrust;
	}

	/**
	 * Direction the starship is heading to, in radians.
	 * The world y axis points down, so the angle must be negated to rotate the sprite.
	 */
	public float rotation
	{
		set
		{
			_rotation = value;
			main.Rotation = -value;
		}

		get => _rotation;
	}

	public int rotatingDir
	{
		set => _rotatingDir = value;

		get => _rotatingDir;
	}

	public int shield
	{
		set
		{
			_shield = value;
			shieldBar.Value = value;
		}

		get => _shield;
	}

	public bool isMine => _isMine;

	// Thrust acceleration is converted from pixels/sec2 to pixels/ms2
	public float thrustAcceleration => (int)settings.GetInt("thrustAccel") / 1000000f;

	// Speed is converted from pixels/sec to pixels/ms
	public float maxSpeed => (int)settings.GetInt("maxSpeed") / 1000f;

	public float rotationSpeed => (int)settings.GetInt("rotationSpeed") * Mathf.Pi / 180f / 1000f;
	#endregion

	//----------------------------------------------------------
	// Callback methods
	//----------------------------------------------------------
	#region
	public override void _Process(double delta)
	{
		base._Process(delta);

		// Set radar rotation to point the level center
		if (_isMine)
			RotateRadar();
	}
	#endregion

	//----------------------------------------------------------
	// Public methods
	//----------------------------------------------------------
	#region
	public void Configure(string type, ISFSObject settings, bool isMine)
	{
		this.settings = settings;
		_isMine = isMine;

		// Load the animation frames of the selected starship model
		// The ship frames are not animated: the thruster state picks the one to display
		sprite.SpriteFrames = ResourceLoader.Load<SpriteFrames>(FRAMES_PATH + type.ToLower() + ".tres");
		sprite.Animation = ANIM_SHIP;
		sprite.Frame = 0;

		// Set the shield bar range
		shieldBar.MaxValue = (int)settings.GetInt("maxShield");

		// Show the radar on the current user's starship only
		radar.Visible = isMine;
	}

	override public void Explode(Vector2? position = null)
	{
		// Hide UI
		radar.Visible = false;
		shieldBar.Visible = false;
		usernameLabel.Visible = false;

		// Show explosion animation
		base.Explode(position);
	}
	#endregion

	//----------------------------------------------------------
	// Private methods
	//----------------------------------------------------------
	#region
	private void RotateRadar()
	{
		// The level center is the origin of the world coordinates system
		radar.Rotation = Mathf.Atan2(-Position.Y, -Position.X);
	}
	#endregion
}
