Editor/ShaderGraphPlus/Compiler/Templates/ShaderTypeInfo.cs
namespace ShaderGraphPlus;

public static partial class ShaderTemplate
{
	public sealed record ShaderTypeInfo( string Title, string Icon, ShaderDomain Domian, IEnumerable<string> SupportStrings, Dictionary<string, TemplateInputPlugInfo> InputPlugs ) : IValid
	{
		public bool IsValid => !string.IsNullOrWhiteSpace( Title ) && InputPlugs.Any();

		internal ShaderTypeInfo() : this( "", "", ShaderDomain.Surface, new List<string>(), new Dictionary<string, TemplateInputPlugInfo>() )
		{
		}

		/// <summary>
		/// Check to see if the provided support string exists.
		/// </summary>
		public bool HasSupport( string supportString ) => SupportStrings.Contains( supportString );

		/// <summary>
		/// Check to see if an input plug with the provided name exists.
		/// </summary>
		public bool HasInputPlug( string name ) => InputPlugs.ContainsKey( name );

		/// <summary>
		/// Try to get the named input plug.
		/// </summary>
		public bool TryGetInputPlug( string name, out TemplateInputPlugInfo plug )
		{
			return InputPlugs.TryGetValue( name, out plug );
		}

		public static implicit operator ShaderTypeInfo( ShaderTemplateResource userTemplate )
		{
			var templatePlugs = new Dictionary<string, TemplateInputPlugInfo>();
			var supportStrings = new List<string>();

			switch ( userTemplate.ShaderDomain )
			{
				case ShaderDomain.Surface:
					{
						if ( userTemplate.ShadingModel == ShadingModel.Lit )
						{
							templatePlugs = ShaderTemplateSurface.DefaultLitInputs;

							supportStrings.Add( SupportsLitShading );
						}
						else
						{
							templatePlugs = ShaderTemplateSurface.DefaultUnlitInputs;

							supportStrings.Add( SupportsUnlitShading );
						}

						if ( !userTemplate.Opacity )
						{
							templatePlugs.Remove( "Opacity" );
						}

						if ( !userTemplate.PositionOffset )
						{
							templatePlugs.Remove( "PositionOffset" );
						}

						if ( userTemplate.OpaqueBlend )
						{
							supportStrings.Add( SupportsOpaqueBlend );
						}
						if ( userTemplate.MaskedBlend )
						{
							supportStrings.Add( SupportsMaskedBlend );
						}
						if ( userTemplate.TranslucentBlend )
						{
							supportStrings.Add( SupportsTranslucentBlend );
						}

						break;
					}
				case ShaderDomain.Sky:
					{
						templatePlugs = ShaderTemplateSky.DefaultInputs;
						break;
					}
				case ShaderDomain.PostProcess:
					{
						templatePlugs = ShaderTemplatePostProcess.DefaultInputs;
						break;
					}
				default:
					throw new NotImplementedException( $"Unknown ShaderDomain '{userTemplate.ShaderDomain}'" );
			}

			if ( userTemplate.EnforceRenderFace )
			{
				switch ( userTemplate.RenderFace )
				{
					case RenderFace.Front:
						supportStrings.Add( SupportsRenderFaceFront );
						break;
					case RenderFace.Back:
						supportStrings.Add( SupportsRenderFaceBack );
						break;
					case RenderFace.Both:
						supportStrings.Add( SupportsRenderFaceBoth );
						break;
				}
			}
			else
			{
				supportStrings.Add( SupportsAllRenderFace );
			}

			return new ShaderTypeInfo(
				userTemplate.Title,
				userTemplate.Icon,
				userTemplate.ShaderDomain,
				supportStrings,
				templatePlugs
			);
		}
	}
}