using System;
using Godot;

public partial class Flashlight : Node
{
	[Export] public Player Player;
	[Export] public GameCamera Camera;

	[Export] public Node2D Circle;
	[Export] public Node2D PlayerCircle;
	[Export] public Polygon2D Polygon;

	[Export] public CollisionShape2D CollisionCircle;
	[Export] public CollisionShape2D CollisionPlayerCircle;
	[Export] public CollisionPolygon2D CollisionPolygon;
	[Export] public CanvasGroup FlashlightGroup;

	[Export] public Curve BrightnessCurve;

	[Export] public AudioStreamPlayer CrankSoundPlayer;

	private float FlashlightRadius = Constants.MaxFlashlightRadius;
	private float FlashlightEnergy = 0;
	private float FlashlightChargeTimeout = 1;

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

		if (CollisionCircle.Shape is not CircleShape2D)
			throw new Exception("Invalid collision shape on the circle");
		if (CollisionPlayerCircle.Shape is not CircleShape2D)
			throw new Exception("Invalid collision shape on the player circle");
	}

	public override void _PhysicsProcess(double delta)
	{
		var playerScreenCenterPosition = Player.Position - Camera.Position;
		var flashlightScreenCenterPosition = Camera.FlashlightPosition - Camera.Position;

		var playerScreenPosition = playerScreenCenterPosition + Constants.HalfScreenSize;
		PlayerCircle.Position = playerScreenPosition;
		CollisionPlayerCircle.Position = playerScreenPosition;

		var d = Camera.FlashlightPosition.DistanceTo(Player.Position);
		FlashlightRadius = Mathf.Lerp(Constants.MinFlashlightRadius, Constants.MaxFlashlightRadius,
			Mathf.Clamp(d - Constants.MinFlashlightDistance, 0,
				Constants.MaxFlashlightDistance - Constants.MinFlashlightDistance) / Constants.MaxFlashlightDistance);

		var flashlightScreenPosition = flashlightScreenCenterPosition + Constants.HalfScreenSize;
		var flashlightScale = FlashlightRadius / Constants.MaxFlashlightRadius;
		Circle.Position = flashlightScreenPosition;
		Circle.Scale = new Vector2(flashlightScale, flashlightScale);
		CollisionCircle.Position = flashlightScreenPosition;
		((CircleShape2D)CollisionCircle.Shape).Radius = FlashlightRadius;

		if (d <= FlashlightRadius)
			Polygon.Visible = false;
		else
		{
			Polygon.Visible = true;

			var a = Mathf.Sqrt(d * d - FlashlightRadius * FlashlightRadius);
			var xy2 = Camera.FlashlightPosition - Player.Position;
			var angle = xy2.Angle();

			var arcsinRd = Mathf.Asin(FlashlightRadius / d);
			var dslkhjdsflkhjsdfhlkjdfsjlk = angle + arcsinRd;
			var xy3 = a * new Vector2(Mathf.Cos(dslkhjdsflkhjsdfhlkjdfsjlk), Mathf.Sin(dslkhjdsflkhjsdfhlkjdfsjlk));
			var dslkhjdsflkhjsdfhlkjdfsjlk2 = angle - arcsinRd;
			var xy4 = a * new Vector2(Mathf.Cos(dslkhjdsflkhjsdfhlkjdfsjlk2), Mathf.Sin(dslkhjdsflkhjsdfhlkjdfsjlk2));

			var polygon = new[]
				{ playerScreenPosition, playerScreenPosition + xy3, playerScreenPosition + xy4 };
			Polygon.Polygon = polygon;
			CollisionPolygon.Polygon = polygon;
		}

		FlashlightChargeTimeout = Mathf.Clamp(FlashlightChargeTimeout - (float)delta, 0, 1);
		if (Input.IsActionJustPressed("flashlight_charge") && FlashlightChargeTimeout <= 0)
		{
			FlashlightChargeTimeout = 1;
			FlashlightEnergy += Constants.FlashlightEnergyPerCharge;
			var rng = new RandomNumberGenerator();
			CrankSoundPlayer.PitchScale = rng.RandfRange(1f, 1.15f);
			CrankSoundPlayer.Play();
		}

		FlashlightEnergy = Mathf.Clamp(FlashlightEnergy - (float)delta  * Constants.FlashlightDischargeModifier,
			0, Constants.MaxFlashlightEnergy);
		FlashlightGroup.Modulate =
			new Color(BrightnessCurve.Sample(FlashlightEnergy / Constants.MaxFlashlightEnergy), 1, 1, 1);
		CollisionCircle.Disabled = CollisionPlayerCircle.Disabled = CollisionPolygon.Disabled = FlashlightEnergy < 10;
	}
}