using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;

namespace Valkyrie
{
    public class AdvancedShaderGUI : BasicShaderGUI
    {
        private static class Styles
        {
            public static string shaderText = "[----------Basic----------]";        
            public static GUIContent mainLabel = EditorGUIUtility.TrTextContent("Main(RGBA)","Main:主贴图(RGBA)+主颜色(RGB)+与光照遮罩通道切换"); //_MainTex _Color
            public static GUIContent BumpMapLabel = EditorGUIUtility.TrTextContent("Normalmap",""); 
            public static GUIContent alphaChangeLabel = EditorGUIUtility.TrTextContent("Alpha Change", "通道切换");
            public static GUIContent MainAlphaLabel = EditorGUIUtility.TrTextContent("MainAlpha", "透明");
            public static readonly GUIContent surfaceType = new GUIContent("Surface Type", "选择模式");
            public static readonly GUIContent cullingText = new GUIContent("Render Face", "渲染单反双面");
            public static readonly GUIContent alphaClipText = new GUIContent("Alpha Clipping", "alphaClip");
            public static readonly GUIContent alphaClipThresholdText = new GUIContent("Threshold","Cutoff");
            public static readonly GUIContent LightLabel = new GUIContent("Light","");
            public static GUIContent shadowFalloffLabel = EditorGUIUtility.TrTextContent("shadow Falloff", "");
            public static GUIContent ReceiveShadowsLabel = EditorGUIUtility.TrTextContent("Receive Shadows", "");
            public static string lightText = "[----------Light----------]";
            //public static GUIContent UseMainLightDir = EditorGUIUtility.TrTextContent("使用主光源的LightDir:");
            public static GUIContent BillboardLabel = EditorGUIUtility.TrTextContent("Billboard",""); 
            public static GUIContent FaceDirLabel = EditorGUIUtility.TrTextContent("FACEDIR","脸部剔除法线Y"); 
            public static GUIContent lightMaskLabel = EditorGUIUtility.TrTextContent("LightMask(RGB)","光照遮罩贴图,R:是否受光照,G:金属,B:是否受高光+是否受光照颜色+是否光朝向镜头"); //_LightMaskTex
            public static GUIContent lightDirLabel = EditorGUIUtility.TrTextContent("Light Dir(XYZ)(光源指向轴的方向,非from):"); //_LightInfo
            public static GUIContent brightnessFactorLabel = EditorGUIUtility.TrTextContent("Min Brightness","明亮因子,0：完全光照颜色，1：白色"); //_BrightnessFactor
            
            public static GUIContent lightMaskParamLabel = EditorGUIUtility.TrTextContent("LightMask Param","光照遮罩图影响(Ramp与Spec)因子,0：完全影响，1：不影响"); //_LightMaskParam
            public static GUIContent lightMaskBackParamLabel = EditorGUIUtility.TrTextContent("Back Param","光照遮罩图暗部影响(光照本身)因子,0：不影响，1：完全影响"); //_LightMaskBackParam
            public static GUIContent GammaLabel = EditorGUIUtility.TrTextContent("Gamma Lut",""); 
            public static GUIContent brightnessIncreaseLabel = EditorGUIUtility.TrTextContent("Brightness Increase","明亮度增强, 渐进增强方式,非相乘因子"); //_BrightnessIncrease
            
            public static string rampText = "[----------Ramp----------]";
            public static GUIContent maskLabel = EditorGUIUtility.TrTextContent("Mask(RGB)","遮罩图,控制Ramp层级,R:增强,G:暗部,B:降低"); //_MaskTexA
            public static GUIContent RampNum4Label = EditorGUIUtility.TrTextContent("Ramp Num4","切换4条ramp");
            public static GUIContent USEGrayMaskLabel = EditorGUIUtility.TrTextContent("Use GrayMask","使用灰度控制ramp");
            public static GUIContent RampNumLabel = EditorGUIUtility.TrTextContent("Ramp Num","ramp条数");
            public static GUIContent rampLabel = EditorGUIUtility.TrTextContent("Ramp(RGB)","Ramp:层级渐变贴图,4层主色+是否切换白色"); //_RampTex _RampColor
            public static GUIContent newRampLabel = EditorGUIUtility.TrTextContent("New Ramp","新Ramp, 增强光照衰减强度"); //_NewRamp
            public static GUIContent brightnessRatioLabel = EditorGUIUtility.TrTextContent("Brightness Ratio","明亮因子,针对Ramp明亮部分增强亮度"); //_BrightnessRatio  
            
            public static readonly GUIContent HightLightLabel = new GUIContent("HightLight","");
            public static string hightLightText = "HightLight:";
            public static GUIContent highLightColorLabel = EditorGUIUtility.TrTextContent("Color(RGB)","高亮颜色"); //_HighLightColor
            public static GUIContent highLightLabel = EditorGUIUtility.TrTextContent("HightLight Factor","高亮因子:相乘因子"); //_HighLight
            public static GUIContent highLightStrengthLabel = EditorGUIUtility.TrTextContent("HightLight Strength","高亮强度:相乘,功能同因子"); //_HighLightStrength

            public static string specularText = "Specular:";
            public static GUIContent specularColorLabel = EditorGUIUtility.TrTextContent("Specular Color", "SpecularColor"); //_Specular Color
            public static GUIContent shininessLabel = EditorGUIUtility.TrTextContent("Shininess", "Shininess"); //_Shininess
            public static GUIContent specSmoothLabel = EditorGUIUtility.TrTextContent("Smoothness", "Smoothness"); //_SpecSmooth
            public static GUIContent SpecStrengthLabel = EditorGUIUtility.TrTextContent("SpecStrength", ""); 
            public static readonly GUIContent queueSlider = new GUIContent("QueueOffset", "");
        }

        public enum SurfaceType
        {
            Opaque,
            Transparent
        }
        public enum RenderFace
        {
            Front = 2,
            Back = 1,
            Both = 0
        }
        /// <summary>
        /// 只在编辑模式下有效， 可以在代码里面用 USE_MAIN_LIGHT_DIR 宏开启
        /// </summary>
        //bool m_useMainLightDir = false;
        //const string g_USE_MAIN_LIGHT_DIR = "USE_MAIN_LIGHT_DIR";
        MaterialProperty MainAlpha = null;
        MaterialProperty mainTex = null;
        MaterialProperty BumpMap = null;
        MaterialProperty alphaChange = null;
        protected MaterialEditor materialEditor { get; set; }
        protected MaterialProperty surfaceTypeProp { get; set; }
        protected MaterialProperty cullingProp { get; set; }
        protected MaterialProperty alphaClipProp { get; set; }
        protected MaterialProperty alphaCutoffProp { get; set; }
        MaterialProperty mainColor = null;
        MaterialProperty shadowFalloff = null;
        MaterialProperty ReceiveShadows = null;

        //MaterialProperty UseMainLightDir = null;
        MaterialProperty Billboard = null;
        MaterialProperty FaceDir = null;
        MaterialProperty lightMaskTex = null;
        //MaterialProperty lightDir = null;
        MaterialProperty brightnessFactor = null;
        MaterialProperty lightMaskParam = null;
        MaterialProperty lightMaskBackParam = null;
        MaterialProperty Gamma = null;
        MaterialProperty brightnessIncrease = null; 

        MaterialProperty maskTex = null;
        MaterialProperty rampTex = null;
        MaterialProperty RampNum4 = null;
        MaterialProperty USEGrayMask = null;
        MaterialProperty RampNum = null;
        MaterialProperty rampColor = null;
        MaterialProperty newRamp = null;
        MaterialProperty brightnessRatio = null;

        MaterialProperty highLightColor = null;
        MaterialProperty highLight = null;
        MaterialProperty highLightStrength = null;

        MaterialProperty specularColor = null;
        MaterialProperty shininess = null;
        MaterialProperty specSmooth = null;
        MaterialProperty SpecStrength = null;
        protected MaterialProperty queueOffsetProp { get; set; }
        bool m_HightLightFoldout;
        public new void FindProperties(MaterialProperty[] props)
        {
            MainAlpha = FindProperty("_MainAlpha", props);
            mainTex = FindProperty("_MainTex", props);
            BumpMap = FindProperty("_BumpMap", props);
            alphaChange = FindProperty("_Alpha_Change", props);

            surfaceTypeProp = FindProperty("_Surface", props);
            cullingProp = FindProperty("_Cull", props);
            alphaClipProp = FindProperty("_AlphaClip", props);
            alphaCutoffProp = FindProperty("_Cutoff", props);

            mainColor = FindProperty("_Color", props);
            shadowFalloff = FindProperty("_shadowFalloff", props);
            ReceiveShadows = FindProperty("_Receive_Shadows", props);

            //UseMainLightDir = FindProperty("_UseMainLightDir", props);
            Billboard = FindProperty("_Billboard", props);
            FaceDir = FindProperty("_FACEDIR", props);
            lightMaskTex = FindProperty("_LightMaskTex", props);
            //lightDir = FindProperty("_LightInfo", props);
            brightnessFactor = FindProperty("_BrightnessFactor", props);
            lightMaskParam = FindProperty("_LightMaskParam", props);
            lightMaskBackParam = FindProperty("_LightMaskBackParam", props);
            Gamma = FindProperty("_Gamma", props);
            brightnessIncrease = FindProperty("_BrightnessIncrease", props);

            maskTex = FindProperty("_MaskTex", props); 
            RampNum4 = FindProperty("_Ramp_Num4", props);           
            USEGrayMask = FindProperty("_USE_GrayMask", props);           
            RampNum = FindProperty("_RampNum", props);           
            rampTex = FindProperty("_RampTex", props);
            rampColor = FindProperty("_RampColor", props);
            newRamp = FindProperty("_NewRamp", props);
            brightnessRatio = FindProperty("_BrightnessRatio", props);

            highLightColor = FindProperty("_HighLightColor", props);
            highLight = FindProperty("_HighLight", props);
            highLightStrength = FindProperty("_HighLightStrength", props);

            specularColor = FindProperty("_SpecColor", props);
            shininess = FindProperty("_Shininess", props);
            specSmooth = FindProperty("_SpecSmooth", props);
            SpecStrength = FindProperty("_SpecStrength", props);
            queueOffsetProp = FindProperty("_QueueOffset", props, false);
        }
        public static void SetupMaterialBlendMode(Material material)
        {
            if (material == null)
                throw new ArgumentNullException("material");
            
            bool alphaClip = material.GetFloat("_AlphaClip") == 1;
            if (alphaClip)
            {
                material.EnableKeyword("_ALPHATEST_ON");
            }
            else
            {
                material.DisableKeyword("_ALPHATEST_ON");
            }

            if (material.GetTexture("_BumpMap") == null ) {
                material.DisableKeyword("_NORMALMAP");
            }
            else
            {
                material.EnableKeyword("_NORMALMAP");
            }

            if (material.GetTexture("_LightMaskTex") == null ) {
                material.SetInt("_LightMask_Off",1);
            }
            else
            {
                material.SetInt("_LightMask_Off",0);
            }

            SurfaceType surfaceType = (SurfaceType)material.GetFloat("_Surface");
            if (surfaceType == SurfaceType.Opaque)
            {
                if (alphaClip)
                {
                    material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest;
                    material.SetOverrideTag("RenderType", "TransparentCutout");
                    material.SetShaderPassEnabled("ShaderTag3", true);
                }
                else
                {
                    material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry;
                    material.SetOverrideTag("RenderType", "Opaque");
                    material.SetFloat("_Cutoff", 0);
                    material.SetShaderPassEnabled("ShaderTag3", false);
                }
                //material.renderQueue += queueOffset;
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
            }
            else
            {
                //var queue = (int) UnityEngine.Rendering.RenderQueue.Transparent;

                if (material.renderQueue > 2450)
                {
                    material.SetOverrideTag("RenderType", "Transparent");
                    material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                    material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                }
                else
                {
                    material.SetOverrideTag("RenderType", "Opaque");
                    material.SetFloat("_Cutoff", 0);
                    material.SetShaderPassEnabled("ShaderTag3", false);
                    material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                    material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                }
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                // General Transparent Material Settings
                material.SetOverrideTag("RenderType", "Transparent");
                if (alphaClip)
                {
                    material.SetInt("_ZWrite", 1);
                }
                else
                {
                    material.SetInt("_ZWrite", 0);
                }
                material.renderQueue = (int) UnityEngine.Rendering.RenderQueue.Transparent;
                material.renderQueue += material.HasProperty("_QueueOffset") ? (int) material.GetFloat("_QueueOffset") : 0;
                //material.renderQueue = queue;
                material.SetShaderPassEnabled("ShaderTag3", true);
            }
        }
        public new void ShaderPropertiesGUI(Material material)
        {
            //m_useMainLightDir = material.IsKeywordEnabled(g_USE_MAIN_LIGHT_DIR);
            //m_useMainLightDir = EditorGUILayout.Toggle(new GUIContent("使用主光源的方向，只在编辑器下有效", "开关USE_MAIN_LIGHT_DIR宏, 只在编辑器下有效， 如果在运行中有效需要自己开启 USE_MAIN_LIGHT_DIR "), m_useMainLightDir);
            //if (m_useMainLightDir)
            //{
            //    material.EnableKeyword(g_USE_MAIN_LIGHT_DIR);
            //}
            //else
            //{
            //    material.DisableKeyword(g_USE_MAIN_LIGHT_DIR);
            //}
            //m_MaterialEditor.ShaderProperty(UseMainLightDir, Styles.UseMainLightDir);
            EditorGUI.BeginChangeCheck();
            {
                GUILayout.Label(Styles.shaderText, EditorStyles.boldLabel);
                m_MaterialEditor.TexturePropertySingleLine(Styles.mainLabel, mainTex, alphaChange);
                //m_MaterialEditor.TexturePropertySingleLine(Styles.mainLabel, mainTex, mainColor,alphaChange);
                m_MaterialEditor.TexturePropertySingleLine(Styles.BumpMapLabel, BumpMap);

                SetupMaterialBlendMode(material);
                if (material == null)
                    throw new ArgumentNullException("material");
                    DoPopup(Styles.surfaceType, surfaceTypeProp, Enum.GetNames(typeof(SurfaceType)));

                EditorGUI.BeginChangeCheck();
                EditorGUI.showMixedValue = cullingProp.hasMixedValue;
                var culling = (RenderFace)cullingProp.floatValue;
                culling = (RenderFace)EditorGUILayout.EnumPopup(Styles.cullingText, culling);
                if (EditorGUI.EndChangeCheck())
                {
                    m_MaterialEditor.RegisterPropertyChangeUndo(Styles.cullingText.text);
                    cullingProp.floatValue = (float)culling;
                    material.doubleSidedGI = (RenderFace)cullingProp.floatValue != RenderFace.Front;
                }

                EditorGUI.showMixedValue = false;

                EditorGUI.BeginChangeCheck();
                EditorGUI.showMixedValue = alphaClipProp.hasMixedValue;
                var alphaClipEnabled = EditorGUILayout.Toggle(Styles.alphaClipText, alphaClipProp.floatValue == 1);
                if (EditorGUI.EndChangeCheck())
                    alphaClipProp.floatValue = alphaClipEnabled ? 1 : 0;
                EditorGUI.showMixedValue = false;

                if (alphaClipProp.floatValue == 1)
                m_MaterialEditor.ShaderProperty(alphaCutoffProp, Styles.alphaClipThresholdText);
                SurfaceType surfaceType = (SurfaceType)material.GetFloat("_Surface");
                if (surfaceType == SurfaceType.Transparent)
                {
                    m_MaterialEditor.ShaderProperty(MainAlpha, Styles.MainAlphaLabel);
                }
                // if (queueOffsetProp != null)
                // {
                //     EditorGUI.BeginChangeCheck();
                //     EditorGUI.showMixedValue = queueOffsetProp.hasMixedValue;
                //     var queue = EditorGUILayout.IntSlider(Styles.queueSlider, (int)queueOffsetProp.floatValue, -550, 100);
                //     if (EditorGUI.EndChangeCheck())
                //         queueOffsetProp.floatValue = queue;
                //     EditorGUI.showMixedValue = false;
                // }
                m_MaterialEditor.ShaderProperty(queueOffsetProp, Styles.queueSlider);

                m_MaterialEditor.ShaderProperty(ReceiveShadows, Styles.ReceiveShadowsLabel);
                if (ReceiveShadows.floatValue == 1)
                {
                m_MaterialEditor.ShaderProperty(shadowFalloff, Styles.shadowFalloffLabel);
                }

                GUILayout.Label(Styles.lightText, EditorStyles.boldLabel);
                m_MaterialEditor.TexturePropertySingleLine(Styles.lightMaskLabel, lightMaskTex,brightnessFactor,Billboard);
                m_MaterialEditor.ShaderProperty(FaceDir, Styles.FaceDirLabel);
                m_MaterialEditor.ShaderProperty(lightMaskParam, Styles.lightMaskParamLabel);
                m_MaterialEditor.ShaderProperty(lightMaskBackParam, Styles.lightMaskBackParamLabel);
                m_MaterialEditor.ShaderProperty(Gamma, Styles.GammaLabel);
                m_MaterialEditor.ShaderProperty(brightnessIncrease, Styles.brightnessIncreaseLabel);

                GUILayout.Label(Styles.rampText, EditorStyles.boldLabel);
                m_MaterialEditor.TexturePropertySingleLine(Styles.maskLabel, maskTex);
                m_MaterialEditor.TexturePropertySingleLine(Styles.rampLabel, rampTex, rampColor , newRamp);
                m_MaterialEditor.ShaderProperty(RampNum4, Styles.RampNum4Label);
                m_MaterialEditor.ShaderProperty(USEGrayMask, Styles.USEGrayMaskLabel);
                m_MaterialEditor.ShaderProperty(RampNum, Styles.RampNumLabel);
                m_MaterialEditor.ShaderProperty(brightnessRatio, Styles.brightnessRatioLabel); 
                m_HightLightFoldout = EditorGUILayout.BeginFoldoutHeaderGroup(m_HightLightFoldout, Styles.HightLightLabel);
                if (m_HightLightFoldout)
                {
                GUILayout.Label(Styles.hightLightText, EditorStyles.boldLabel);
                m_MaterialEditor.ShaderProperty(highLightColor, Styles.highLightColorLabel);
                m_MaterialEditor.ShaderProperty(highLight, Styles.highLightLabel);
                m_MaterialEditor.ShaderProperty(highLightStrength, Styles.highLightStrengthLabel);

                GUILayout.Label(Styles.specularText, EditorStyles.boldLabel);
                m_MaterialEditor.ShaderProperty(specularColor, Styles.specularColorLabel);
                m_MaterialEditor.ShaderProperty(shininess, Styles.shininessLabel);
                m_MaterialEditor.ShaderProperty(specSmooth, Styles.specSmoothLabel);
                m_MaterialEditor.ShaderProperty(SpecStrength, Styles.SpecStrengthLabel);
                EditorGUILayout.Space();
                }
                EditorGUILayout.EndFoldoutHeaderGroup();
                ;
            }
            if (EditorGUI.EndChangeCheck())
            {
                
            }
        }
        public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] props)
        {
            base.FindProperties(props);
            FindProperties(props);
            m_MaterialEditor = materialEditor;
            Material material = materialEditor.target as Material;
            ShaderPropertiesGUI(material);
            base.ShaderPropertiesGUI(material);
            m_MaterialEditor.RenderQueueField();
            m_MaterialEditor.EnableInstancingField();
        }
         public void DoPopup(GUIContent label, MaterialProperty property, string[] options)
        {
            DoPopup(label, property, options, m_MaterialEditor);
        }

        public static void DoPopup(GUIContent label, MaterialProperty property, string[] options, MaterialEditor materialEditor)
        {
            if (property == null)
                throw new ArgumentNullException("property");

            EditorGUI.showMixedValue = property.hasMixedValue;

            var mode = property.floatValue;
            EditorGUI.BeginChangeCheck();
            mode = EditorGUILayout.Popup(label, (int)mode, options);
            if (EditorGUI.EndChangeCheck())
            {
                materialEditor.RegisterPropertyChangeUndo(label.text);
                property.floatValue = mode;
            }

            EditorGUI.showMixedValue = false;
        }
    }
}
