using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LitJson;
using System;
using System.Reflection;

namespace FVS
{
    public abstract class FVSBaseStyle : MonoBehaviour
    {
        // Start is called before the first frame update
        [HideInInspector]
        public string configData;

        [LocalizedHeader("Header_StyleDisplayName")]
        public string displayName;

        public virtual void Awake()
        {
            //if (configData != "" && configData != null)
            //    ReactCompoentManager.Instance.configUpdated += OnUpdateConfig;
        }
        void Start()
        {

        }

        // Update is called once per frame
        void Update()
        {

        }

        public void LoadConfig()
        {
            JsonWriter writer = new JsonWriter();

            var displayName = gameObject.name;
            if (this.displayName != "")
            {
                displayName = this.displayName;
            }

            writer.WriteObjectStart();
            writer.WritePropertyName("gameObject");
            writer.Write(gameObject.name);
            writer.WritePropertyName("displayName");
            writer.Write(displayName);
            writer.WritePropertyName("properties");
            writer.WriteArrayStart();

            MethodInfo[] methodinfos = GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            Dictionary<string, MethodInfo> setMethodDict = new Dictionary<string, MethodInfo>();

            foreach (MethodInfo method in methodinfos)
            {
                var isSetter = Attribute.IsDefined(method, typeof(FVSSetConfigAttribute));
                if (isSetter)
                {
                    FVSSetConfigAttribute attribute = (FVSSetConfigAttribute)Attribute.GetCustomAttribute(method, typeof(FVSSetConfigAttribute));
                    setMethodDict.Add(attribute.name, method);
                }
            }

            foreach (MethodInfo method in methodinfos)
            {
                var isDef = Attribute.IsDefined(method, typeof(FVSGetConfigAttribute));
                if (isDef)
                {
                    writer.WriteObjectStart();
                    FVSGetConfigAttribute attribute = (FVSGetConfigAttribute)Attribute.GetCustomAttribute(method, typeof(FVSGetConfigAttribute));
                    object data = method.Invoke(this, new object[0]);

                    writer.WritePropertyName("name");
                    writer.Write(attribute.name);
                    writer.WritePropertyName("displayName");
                    writer.Write(attribute.displayName);
                    //  getter & setter
                    writer.WritePropertyName("getter");
                    writer.Write(method.Name);
                    if (setMethodDict.ContainsKey(attribute.name))
                    {
                        writer.WritePropertyName("setter");
                        writer.Write(setMethodDict[attribute.name].Name);
                    }

                    if (typeof(ValueTypeBase).IsAssignableFrom(data.GetType()))
                    {

                        ((ValueTypeBase)data).WriteJson(writer);
                    }
                    writer.WriteObjectEnd();
                }
            }
            writer.WriteArrayEnd();
            writer.WriteObjectEnd();

            configData = writer.ToString();
        }

        [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
        public class FVSSetConfigAttribute : Attribute
        {
            public string name;
            public FVSSetConfigAttribute(string name)
            {
                this.name = name;
            }
        }

        [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
        public class FVSGetConfigAttribute : Attribute
        {
            public string name;
            public string displayName;
            public FVSGetConfigAttribute(string name, string displayName)
            {
                this.name = name;
                this.displayName = displayName;
            }
        }

        [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
        public class FVSActionConfigAttribute : Attribute
        {
            public string displayName;
            public FVSActionConfigAttribute(string displayName)
            {
                this.displayName = displayName;
            }
        }

        public enum ValueType
        {
            Text,
            Color,
            Number,
            Vector3,
            Select,
        }

        public abstract class ValueTypeBase : object
        {
            public ValueType type;
            public object value;

            public ValueTypeBase(ValueType type, object value) 
            {
                this.type = type;
                this.value = value;
            }

            public virtual void WriteJson(JsonWriter writer)
            {
                writer.WritePropertyName("type");
                writer.Write(type.ToString());
                if (this.value != null)
                {
                    writer.WritePropertyName("value");
                    this.WriteValue(writer);
                }
            }

            protected abstract void WriteValue(JsonWriter writer);
        }

        public class TextType : ValueTypeBase
        {
            public TextType(string value) : base(ValueType.Text, value) {}

            protected override void WriteValue(JsonWriter writer)
            {
                writer.Write((string)value);
            }
        }

        public class ColorType : ValueTypeBase
        {
            public ColorType(Color value) : base(ValueType.Color, value) {}

            protected override void WriteValue(JsonWriter writer)
            {
                writer.Write(BaseUtils.Color2Hex((Color) value));
            }
        }

        public class NumberType : ValueTypeBase
        {
            public float min;
            public float max;
            public float step;
            public NumberType(float value, float min = 0, float max = 1, float step = 1) : base(ValueType.Number, value)
            {
                this.min = min;
                this.max = max;
                this.step = step;
            }

            protected override void WriteValue(JsonWriter writer)
            {
                writer.Write((float)value);
                if (min != max)
                {
                    writer.WritePropertyName("min");
                    writer.Write((float)min);
                    writer.WritePropertyName("max");
                    writer.Write((float)max);
                    writer.WritePropertyName("step");
                    writer.Write((float)step);
                }
            }
        }

        public class SelectType : ValueTypeBase
        {
            public List<SelectOption> options;

            public SelectType(string value, List<SelectOption> options) : base(ValueType.Select, value)
            {
                this.options = options;
            }

            protected override void WriteValue(JsonWriter writer)
            {
                writer.Write((string)value);
                writer.WritePropertyName("options");
                writer.WriteArrayStart();
                foreach (SelectOption option in options)
                {
                    writer.WriteObjectStart();
                    writer.WritePropertyName("name");
                    writer.Write(option.name);
                    writer.WritePropertyName("value");
                    writer.Write(option.value);
                    writer.WriteObjectEnd();
                }
                writer.WriteArrayEnd();
            }
        }

        public class Vector3Type : ValueTypeBase
        {
            public Vector3Type(Vector3 value) : base(ValueType.Vector3, value) { }

            protected override void WriteValue(JsonWriter writer)
            {
                writer.WriteArrayStart();
                Vector3 vector3 = (Vector3)value;
                writer.Write(vector3.x);
                writer.Write(vector3.y);
                writer.Write(vector3.z);
                writer.WriteArrayEnd();
            }
        }

        public class SelectOption
        {
            public string name;
            public string value;

            public SelectOption(string name, string value)
            {
                this.name = name;
                this.value = value;
            }
        }
    }
}
