using System.Collections.Generic;
using Godot;

namespace AceFieldNewHorizon.Scripts.System;

public partial class BuildingRegistry : Node
{
	public record BuildingData(
		PackedScene Scene,
		Dictionary<string, int> Cost,
		int Durability,
		float BuildTime
	);

	private Dictionary<string, BuildingData> _registry = new();

	[Export] public string JsonPath { get; set; } = "res://Data/Buildings.json";

	public override void _Ready()
	{
		LoadFromJson(JsonPath);
	}

	public void LoadFromJson(string path)
	{
		var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
		if (file == null)
		{
			GD.PrintErr($"[BuildingRegistry] Failed to open {path}");
			return;
		}

		var text = file.GetAsText();
		file.Close();

		var json = new Json();
		var error = json.Parse(text);
		if (error != Error.Ok)
		{
			GD.PrintErr($"[BuildingRegistry] Failed to parse JSON: {json.GetErrorMessage()}");
			return;
		}

		var dict = (Godot.Collections.Dictionary)json.Data;

		foreach (string key in dict.Keys)
		{
			// Each entry is a Dictionary with keys: "scene", "cost", "durability", "buildTime"
			var buildingDict = dict[key].AsGodotDictionary();

			// Parse scene
			var scenePath = buildingDict.ContainsKey("scene") ? buildingDict["scene"].AsString() : null;
			if (string.IsNullOrEmpty(scenePath))
			{
				GD.PrintErr($"[BuildingRegistry] No scene path for '{key}'");
				continue;
			}

			var scene = GD.Load<PackedScene>(scenePath);
			if (scene == null)
			{
				GD.PrintErr($"[BuildingRegistry] Failed to load scene for '{key}' at {scenePath}");
				continue;
			}

			// Parse cost
			Dictionary<string, int> cost = new();
			if (buildingDict.TryGetValue("cost", out var value))
			{
				var costDict = value.AsGodotDictionary();
				foreach (string mat in costDict.Keys)
				{
					int val;
					var obj = costDict[mat];
					if (obj.VariantType == Variant.Type.PackedInt64Array)
						val = (int)obj.AsInt64();
					else if (obj.VariantType == Variant.Type.PackedInt32Array)
						val = obj.AsInt32();
					else
						int.TryParse(obj.ToString(), out val);
					cost[mat] = val;
				}
			}

			// Parse durability
			var durability = 0;
			if (buildingDict.TryGetValue("durability", out var dObj))
			{
				if (dObj.VariantType == Variant.Type.PackedInt64Array)
					durability = (int)dObj.AsInt64();
				else if (dObj.VariantType == Variant.Type.PackedInt32Array)
					durability = dObj.AsInt32();
				else
					int.TryParse(dObj.ToString(), out durability);
			}

			// Parse buildTime
			var buildTime = 0f;
			if (buildingDict.TryGetValue("buildTime", out var bObj))
			{
				switch (bObj.VariantType)
				{
					case Variant.Type.PackedFloat32Array or Variant.Type.PackedFloat64Array:
						buildTime = (float)bObj.AsDouble();
						break;
					case Variant.Type.PackedInt64Array:
						buildTime = bObj.AsInt64();
						break;
					case Variant.Type.PackedInt32Array:
						buildTime = bObj.AsInt32();
						break;
					default:
						float.TryParse(bObj.ToString(), out buildTime);
						break;
				}
			}

			var buildingData = new BuildingData(scene, cost, durability, buildTime);
			_registry[key] = buildingData;
			GD.Print($"[BuildingRegistry] Loaded building '{key}' from {scenePath}");
		}

		GD.Print($"[BuildingRegistry] Loaded {_registry.Count} buildings");
	}

	public BuildingData GetBuilding(string id)
	{
		_registry.TryGetValue(id, out var data);
		return data;
	}
}
