using System;

namespace GlitchyEngine.Content;

public class AssetIdentifier
{
	public const String ResourcesPrefix = "Resources/";
	public const String AssetsPrefix = "Assets/";

	private String _fullIdentifier ~ delete:append _;

	private bool _isResource;

	private int _subassetSeperator;

	public StringView FullIdentifier => _fullIdentifier;
	public StringView AssetIdentifier => _subassetSeperator > 0 ? StringView(_fullIdentifier, 0, _subassetSeperator) : _fullIdentifier;
	public StringView SubassetIdentifier => _subassetSeperator > 0 ? StringView(_fullIdentifier, _subassetSeperator + 1) : .();

	public bool IsResource => _isResource;

	[AllowAppend]
	public this(StringView assetIdentifier)
	{
		String identifier = append String(assetIdentifier);
		_fullIdentifier = identifier;

		Fixup(_fullIdentifier);

		_subassetSeperator = _fullIdentifier.IndexOf(':', 0);

		_isResource = _fullIdentifier.StartsWith(ResourcesPrefix);
	}

	[AllowAppend]
	public this(StringView assetIdentifier, StringView subAssetIdentifier)
	{
		String fullIdentifier = append String(assetIdentifier.Length + 1 + subAssetIdentifier.Length);
		fullIdentifier.AppendF($"{assetIdentifier}:{subAssetIdentifier}");

		Fixup(fullIdentifier);

		_fullIdentifier = fullIdentifier;
		_subassetSeperator = _fullIdentifier.IndexOf(':', 0);
	}

	public static StringView operator implicit(AssetIdentifier identifier) => identifier.FullIdentifier;

	public const char8 DirectorySeparatorChar = '/';

	/// Removes or unifies potential platform specific or file-path related stuff in the given asset identifier
	public static void Fixup(String assetIdentifier)
	{
		int dotIndex = 0;

		assetIdentifier.Replace('\\', DirectorySeparatorChar);
		
		// Replace /./ stuff
		while ((dotIndex = assetIdentifier.IndexOf('.', dotIndex)) != -1)
		{
			char8 lastChar = '\0';
			char8 nextChar = '\0';

			int nextIndex = dotIndex + 1;
			if (nextIndex < assetIdentifier.Length)
				nextChar = assetIdentifier[nextIndex];

			int lastIndex = dotIndex - 1;
			if (lastIndex < assetIdentifier.Length)
				lastChar = assetIdentifier[nextIndex];

			// We either need to have a slash on both sides, or we have to be at the start or end of the string
			if ((lastChar == '\0' || lastChar == DirectorySeparatorChar) &&
				(lastChar == '\0' || lastChar == DirectorySeparatorChar))
			{
				if (lastChar != '\0')
					assetIdentifier.Remove(lastIndex, 2);
				else
					assetIdentifier.Remove(dotIndex, 2);
			}
			else
			{
				// Skip the dot
				dotIndex++;
			}
		}

		if (assetIdentifier.StartsWith(DirectorySeparatorChar))
			assetIdentifier.Remove(0, 1);

		assetIdentifier.EnsureNullTerminator();
	}

	public override void ToString(String strBuffer)
	{
		strBuffer.Append(FullIdentifier);
	}
}
