using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor;

namespace YooAsset.Editor
{
	[Serializable]
	public class ShaderVariantCollectionManifest
	{
		[Serializable]
		public class ShaderVariantElement
		{
			/// <summary>
			///  Pass type to use in this variant.
			/// </summary>
			public PassType PassType;

			/// <summary>
			/// Array of shader keywords to use in this variant.
			/// </summary>
			public string[] Keywords;
		}

		[Serializable]
		public class ShaderVariantInfo
		{
			/// <summary>
			/// 着色器资源路径.
			/// </summary>
			public string AssetPath;

			/// <summary>
			/// 着色器名称
			/// </summary>
			public string ShaderName;

			/// <summary>
			/// 着色器变种总数
			/// </summary>
			public int ShaderVariantCount = 0;

			/// <summary>
			/// 着色器变种列表
			/// </summary>
			public List<ShaderVariantElement> ShaderVariantElements = new List<ShaderVariantElement>(1000);
		}


		/// <summary>
		/// Number of shaders in this collection
		/// </summary>
		public int ShaderTotalCount;

		/// <summary>
		/// Number of total varians in this collection
		/// </summary>
		public int VariantTotalCount;

		/// <summary>
		/// Shader variants info list.
		/// </summary>
		public List<ShaderVariantInfo> ShaderVariantInfos = new List<ShaderVariantInfo>(1000);

		/// <summary>
		/// 添加着色器变种信息
		/// </summary>
		public void AddShaderVariant(string assetPath, string shaderName, PassType passType, string[] keywords)
		{
			var info = GetOrCreateShaderVariantInfo(assetPath, shaderName);
			ShaderVariantElement element = new ShaderVariantElement();
			element.PassType = passType;
			element.Keywords = keywords;
			info.ShaderVariantElements.Add(element);
			info.ShaderVariantCount++;
		}
		private ShaderVariantInfo GetOrCreateShaderVariantInfo(string assetPath, string shaderName)
		{
			var selectList = ShaderVariantInfos.Where(t => t.ShaderName == shaderName && t.AssetPath == assetPath).ToList();
			if (selectList.Count == 0)
			{
				ShaderVariantInfo newInfo = new ShaderVariantInfo();
				newInfo.AssetPath = assetPath;
				newInfo.ShaderName = shaderName;
				ShaderVariantInfos.Add(newInfo);
				return newInfo;
			}

			if (selectList.Count != 1)
				throw new Exception("Should never get here !");

			return selectList[0];
		}


		/// <summary>
		/// 解析SVC文件并将数据写入到清单
		/// </summary>
		public static ShaderVariantCollectionManifest Extract(ShaderVariantCollection svc)
		{
			var manifest = new ShaderVariantCollectionManifest();
			manifest.ShaderTotalCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionShaderCount();
			manifest.VariantTotalCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionVariantCount();

			using (var so = new SerializedObject(svc))
			{
				var shaderArray = so.FindProperty("m_Shaders.Array");
				if (shaderArray != null && shaderArray.isArray)
				{
					for (int i = 0; i < shaderArray.arraySize; ++i)
					{
						var shaderRef = shaderArray.FindPropertyRelative($"data[{i}].first");
						var shaderVariantsArray = shaderArray.FindPropertyRelative($"data[{i}].second.variants");
						if (shaderRef != null && shaderRef.propertyType == SerializedPropertyType.ObjectReference && shaderVariantsArray != null && shaderVariantsArray.isArray)
						{
							var shader = shaderRef.objectReferenceValue as Shader;
							if (shader == null)
							{
								throw new Exception("Invalid shader in ShaderVariantCollection file.");
							}

							string shaderAssetPath = AssetDatabase.GetAssetPath(shader);
							string shaderName = shader.name;

							// 添加变种信息
							for (int j = 0; j < shaderVariantsArray.arraySize; ++j)
							{
								var propKeywords = shaderVariantsArray.FindPropertyRelative($"Array.data[{j}].keywords");
								var propPassType = shaderVariantsArray.FindPropertyRelative($"Array.data[{j}].passType");
								if (propKeywords != null && propPassType != null && propKeywords.propertyType == SerializedPropertyType.String)
								{
									string[] keywords = propKeywords.stringValue.Split(' ');
									PassType pathType = (PassType)propPassType.intValue;
									manifest.AddShaderVariant(shaderAssetPath, shaderName, pathType, keywords);
								}
							}
						}
					}
				}
			}

			return manifest;
		}
	}
}