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

namespace NodeWar;

public enum NoduleType
{
	Base,
	Connector,
}

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

	[Export]
	private NoduleType _noduleType;

	[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; set; } = [];

	[Signal]
	public delegate void NoduleBuiltEventHandler();

	[Signal]
	public delegate void BuildingCanceledEventHandler();

	[Node]
	private Node2D _gfx;

	[Node]
	private CollisionShape2D _baseCollision;

	public override void _Ready()
	{
		AreaEntered += OnAreaEntered;
		AreaExited += OnAreaExited;

		switch (_noduleType)
		{
			case NoduleType.Base:
				_gfx.Scale = new Vector2(2, 2);
				Modulate = Colors.Red;
				_baseCollision.Disabled = false;
				break;
			case NoduleType.Connector:
				break;
			default:
				throw new ArgumentOutOfRangeException();
		}

		QueueRedraw();
	}

	private void OnAreaEntered(Area2D area)
	{
		if (area is Nodule nodule)
		{
			if (nodule.BuildMode)
			{
				return;
			}

			ConnectedNodules.Add(nodule);
		}
	}

	private void OnAreaExited(Area2D area)
	{
		if (area is Nodule nodule)
		{
			if (nodule.BuildMode)
			{
				return;
			}

			ConnectedNodules.Remove(nodule);
		}
	}

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

			if (Input.IsMouseButtonPressed(MouseButton.Left))
			{
				EmitSignalNoduleBuilt();
				BuildMode = false;

				MouseEntered += OnMouseEntered;
			}

			if (Input.IsMouseButtonPressed(MouseButton.Right))
			{
				EmitSignalBuildingCanceled();
				BuildMode = false;
				QueueFree();
			}
		}
		else
		{
			Age += GrowthFactor * delta.ToFloat();
			Age = MathF.Min(Age, 1);

			QueueRedraw();
		}

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

	private void OnMouseEntered()
	{
		GD.Print("Mouse entered");
	}

	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)
			);
		}
	}

	public override void _Notification(int what)
	{
		if (what == NotificationSceneInstantiated)
		{
			WireNodes();
		}
	}
}
