using System;
using System.Collections.Generic;
using Godot;
using NodeWar.scripts;

namespace NodeWar;

public enum NoduleType
{
	Base,
	Connector,
}

[SceneTree]
public partial class Nodule : Area2D
{
	private const float GrowthFactor = 0.01f;

	[Export]
	private NoduleType _noduleType;

	private bool _growAreaInside;

	[Export]
	public float MaxRadius { get; set; } = 360;

	[Export]
	public bool BuildMode { get; set; } = false;

	[Export]
	public float Age { get; set; } = 0;

	[Export]
	public PackedScene RootScene { get; set; }

	public List<Nodule> ConnectedNodules { get; } = [];

	[Signal]
	public delegate void NoduleBuiltEventHandler();

	[Signal]
	public delegate void BuildingCanceledEventHandler();

	public override void _Ready()
	{
		_.ConnectionArea.NoduleEntered += HandleNoduleEntered;
		_.ConnectionArea.NoduleExited += HandleNoduleExited;

		switch (_noduleType)
		{
			case NoduleType.Base:
				Modulate = Colors.Red;

				_.Gfx.Get().Scale = new Vector2(2, 2);
				_.BaseCollision.Disabled = false;

				BuildNode();
				break;
			case NoduleType.Connector:
				break;
			default:
				throw new ArgumentOutOfRangeException();
		}

		QueueRedraw();
	}

	public override void _Process(double delta)
	{
		if (BuildMode)
		{
			GlobalPosition = GetGlobalMousePosition();

			if (Input.IsActionJustPressed(MyInput.MouseLeft))
			{
				BuildNode();
			}

			if (Input.IsMouseButtonPressed(MouseButton.Right))
			{
				EmitSignalBuildingCanceled();
				BuildMode = false;
				QueueFree();
			}
		}
		else
		{
			if (Input.IsActionJustPressed(MyInput.MouseLeft) && _growAreaInside && !BuildMode)
			{
				var newNodule = Instantiator.Instantiate<Nodule>();
				newNodule.BuildMode = true;
				GetParent().AddChild(newNodule);
				newNodule.GlobalPosition = GlobalPosition;
			}

			Age += GrowthFactor * delta.ToFloat();
			Age = MathF.Min(Age, 1);

			QueueRedraw();
		}

		// TODO: replace with line2d?
		QueueRedraw();
	}

	public override void _Draw()
	{
		foreach (var nodule in ConnectedNodules)
		{
			if (BuildMode)
			{
				DrawDashedLine(
					Vector2.Zero,
					nodule.GlobalPosition - GlobalPosition,
					Colors.White,
					2f,
					dash: 4f,
					antialiased: true
				);
			}
		}

		var value = 200 * Age;

		if (!BuildMode)
		{
			DrawRect(
				new Rect2(-value / 2, -value / 2, value, value),
				new Color(Colors.WhiteSmoke, 0.4f)
			);
		}
	}

	private void HandleNoduleEntered(Nodule nodule)
	{
		ConnectedNodules.Add(nodule);
	}

	private void HandleNoduleExited(Nodule nodule)
	{
		ConnectedNodules.Remove(nodule);
	}

	private void BuildNode()
	{
		EmitSignalNoduleBuilt();
		BuildMode = false;

		// try connecting built nodule to connected ones
		foreach (var connectedNodule in ConnectedNodules)
		{
			BuildManager.Instance.RegisterConnection(this, connectedNodule);
		}

		_.GrowArea.Get().MouseEntered += () =>
		{
			_growAreaInside = true;
		};

		_.GrowArea.Get().MouseExited += () =>
		{
			_growAreaInside = false;
		};
	}
}
