using Godot;
using System;
using System.Collections.Generic;
using System.Linq;

public partial class Tile
{
	public Dictionary<string, MeshInstance3D> tileMeshes;
	public string collapsedMesh;
	Random rand = new Random();
	public Vector3 Position;
	public Vector2I GridPosition;
	public Node3D ContentNode;

	public bool containsLight, containsDecoration, containsResource;


	public void SetMeshes(Dictionary<string, MeshInstance3D> tileMeshes)
	{
		this.tileMeshes = new Dictionary<string, MeshInstance3D>(tileMeshes);
	}

	public string Collapse(string tile)
	{
		if (collapsedMesh != null) return "";
		if (tileMeshes.Keys.Count <= 0) return "ERR";
		collapsedMesh = (tile.Length > 0) ? tile : ChooseWeighted();
		tileMeshes.Clear();
		return collapsedMesh;
	}

	private string ChooseWeighted()
	{
		float totalWeight = 0f;

		foreach (string tile in tileMeshes.Keys)
		{
			totalWeight += WFC.weights[tile];
		}

		float r = (float)(rand.NextDouble() * totalWeight);

		float cumulative = 0f;

		foreach (string tile in tileMeshes.Keys)
		{
			cumulative += WFC.weights[tile];

			if (r <= cumulative)
				return tile;
		}

		return "junction";
	}

	public int Propagate(HashSet<string> possibleKeys)
	{
		int amountRemoved = 0;
		if (collapsedMesh != null) return 0;
		foreach (string key in tileMeshes.Keys.ToList())
		{
			if (!possibleKeys.Contains(key))
			{
				tileMeshes.Remove(key);
				amountRemoved++;
			}
		}
		if (tileMeshes.Count == 0) return int.MaxValue;
		return amountRemoved;
	}

	public void Reset(Dictionary<string, MeshInstance3D> tileMeshes)
	{
		collapsedMesh = null;
		SetMeshes(tileMeshes);
	}

	public void SpawnContent(Dictionary<string, MeshInstance3D> contentMeshes, Transform3D transform, List<Placeholder> placeholders)
	{
		foreach (Placeholder placeholder in placeholders)
		{
			if (containsLight && placeholder.name == "light") SpawnLight(contentMeshes["light"], placeholder, transform);
			else if (containsResource && placeholder.name == "resource") SpawnResource(contentMeshes["resource"], placeholder, transform);
			else if (containsDecoration && placeholder.name != "light" && placeholder.name != "resource") SpawnDecorations(contentMeshes, placeholder, transform);
		}
	}

	private void SpawnLight(MeshInstance3D lightMesh, Placeholder placeholder, Transform3D transform)
	{
		MeshInstance3D light = new MeshInstance3D
		{
			Mesh = lightMesh.Mesh,
			Position = placeholder.transform.Origin
		};
		OmniLight3D lightSource = new OmniLight3D()
		{
			OmniAttenuation = 2f,
			LightColor = GameData.lightColor,
			ShadowEnabled = true,
			LightEnergy = 100f,
			LightIndirectEnergy = 1.5f,
			OmniRange = 20f,
			Position = placeholder.transform.Origin
		};
		lightSource.Position.MoveToward(transform.Origin, 0.1f);
		LightHandler.lights.Add(lightSource);
		light.AddChild(lightSource);
		ContentNode.AddChild(light);
		light.LookAt(transform.Origin, Vector3.Up);
	}

	private void SpawnResource(MeshInstance3D resourceMesh, Placeholder placeholder, Transform3D transform)
	{
		MeshInstance3D resource = new MeshInstance3D
		{
			Mesh = resourceMesh.Mesh,
			Position = placeholder.transform.Origin
		};
		ContentNode.AddChild(resource);
		resource.LookAt(transform.Origin, Vector3.Up);
	}

	private void SpawnDecorations(Dictionary<string, MeshInstance3D> contentMeshes, Placeholder placeholder, Transform3D transform)
	{
		foreach (string key in contentMeshes.Keys)
		{
			if (key.ToLower() != placeholder.name) continue;
			MeshInstance3D decoration = new MeshInstance3D
			{
				Mesh = contentMeshes[key].Mesh,
				Position = placeholder.transform.Origin
			};
			ContentNode.AddChild(decoration);
			decoration.LookAt(transform.Origin, Vector3.Up);
		}
	}
}
