using System.Collections.Generic;
using UnityEngine.Events;
using UnityEngine.UI;

namespace WS
{
    ///<summary>属性绑定基类</summary>
    public class BindablePropertyBase : WSComponent
    {
    }

    ///<summary>属性绑定</summary>
    public class BindableProperty<T> : BindablePropertyBase
    {
        ///<summary>回调</summary>
        public UnityAction<T> OnValueChanged;

        private T _value;
        ///<summary>值</summary>
        public T Value
        {
            get { return _value; }
            set
            {
                if (!Equals(_value, value))
                {
                    _value = value;
                    OnValueChanged?.Invoke(_value);
                }
            }
        }

        public override void Dispose()
        {
            base.Dispose();
            OnValueChanged = null;
            _value = default(T);
        }
    }

    ///<summary>模型</summary>
    public abstract class Model : WSComponent
    {
        //<summary>属性</summary>
        private List<BindablePropertyBase> Propertys = new List<BindablePropertyBase>();
        ///<summary>UI事件</summary>
        private List<UnityEventBase> UnityEvents = new List<UnityEventBase>();

        ///<summary>创建属性</summary>
        public BindableProperty<T> CreateProperty<T>()
        {
            BindableProperty<T> property = ComponentFactory.CreateWithParent<BindableProperty<T>>(this);
            Propertys.Add(property);
            return property;
        }

        ///<summary>ViewModel属性初始化</summary>
        public abstract void InitProperty();

        /// <summary>绑定属性</summary>
        /// <param name="inputfield">输入框</param>
        /// <param name="property">属性 string</param>
        /// <param name="valueChanged">属性值改变回调</param>
        public void Bind(InputField inputfield, BindableProperty<string> property, UnityAction<string> valueChanged = null)
        {
            property.OnValueChanged += delegate
            {
                inputfield.text = property.Value;
                valueChanged?.Invoke(property.Value);
            };
            inputfield.onValueChanged.AddListener((x) =>
            {
                property.Value = x;
            });
            UnityEvents.Add(inputfield.onValueChanged);
        }
        /// <summary>绑定属性</summary>
        /// <param name="inputfield">输入框</param>
        /// <param name="property">属性 string</param>
        /// <param name="valueChanged">属性值改变回调</param>
        public void Bind(TMPro.TMP_InputField inputfield, BindableProperty<string> property, UnityAction<string> valueChanged = null)
        {
            property.OnValueChanged += delegate
            {
                inputfield.text = property.Value;
                valueChanged?.Invoke(property.Value);
            };
            inputfield.onValueChanged.AddListener((x) =>
            {
                property.Value = x;
            });
            UnityEvents.Add(inputfield.onValueChanged);
        }
        /// <summary>绑定属性</summary>
        /// <param name="inputfield">输入框</param>
        /// <param name="property">属性 int</param>
        /// <param name="valueChanged">属性值改变回调</param>
        public void Bind(InputField inputfield, BindableProperty<int> property, UnityAction<int> valueChanged = null)
        {
            property.OnValueChanged += delegate
            {
                inputfield.text = property.Value.ToString();
                valueChanged?.Invoke(property.Value);
            };
            inputfield.onValueChanged.AddListener((x) =>
            {
                int num = int.Parse(x);
                property.Value = num;
            });
            UnityEvents.Add(inputfield.onValueChanged);
        }

        /// <summary>绑定属性</summary>
        /// <param name="inputfield">输入框</param>
        /// <param name="property">属性 long</param>
        /// <param name="valueChanged">属性值改变回调</param>
        public void Bind(InputField inputfield, BindableProperty<long> property, UnityAction<long> valueChanged = null)
        {
            property.OnValueChanged += delegate
            {
                inputfield.text = property.Value.ToString();
                valueChanged?.Invoke(property.Value);
            };
            inputfield.onValueChanged.AddListener((x) =>
            {
                long num = long.Parse(x);
                property.Value = num;
            });
            UnityEvents.Add(inputfield.onValueChanged);
        }

        /// <summary>绑定属性</summary>
        /// <param name="text">文本框</param>
        /// <param name="property">属性</param>
        public void Bind(Text text, BindableProperty<string> property)
        {
            text.text = property.Value;
            property.OnValueChanged += (x) =>
            {
                text.text = property.Value.ToString();
            };
        }

        /// <summary>绑定属性</summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="text">文本框</param>
        /// <param name="property">属性</param>
        public void Bind<T>(Text text, BindableProperty<T> property)
        {
            text.text = property.Value.ToString();
            property.OnValueChanged += (x) =>
            {
                text.text = property.Value.ToString();
            };
        }

        /// <summary>绑定属性</summary>
        /// <param name="toggle">开关</param>
        /// <param name="property">属性</param>
        /// <param name="valueChanged">属性值改变回调</param>
        public void Bind(Toggle toggle, BindableProperty<bool> property, UnityAction<bool> valueChanged = null)
        {
            property.OnValueChanged += delegate
             {
                 toggle.isOn = property.Value;
                 valueChanged?.Invoke(property.Value);
             };
            toggle.onValueChanged.AddListener((x) =>
            {
                property.Value = x;
            });
            UnityEvents.Add(toggle.onValueChanged);
        }

        /// <summary>绑定属性</summary>
        /// <param name="slider">滑杆</param>
        /// <param name="property">属性</param>
        /// <param name="valueChanged">属性值改变回调</param>
        public void Bind(Slider slider, BindableProperty<float> property, UnityAction<float> valueChanged = null)
        {
            property.OnValueChanged += delegate
            {
                slider.value = property.Value;
                valueChanged?.Invoke(property.Value);
            };
            slider.onValueChanged.AddListener((x) =>
            {
                property.Value = x;
            });
            UnityEvents.Add(slider.onValueChanged);
        }

        /// <summary>绑定属性</summary>
        /// <param name="scrollbar">滚动条</param>
        /// <param name="property">属性</param>
        /// <param name="valueChanged">属性值改变回调</param>
        public void Bind(Scrollbar scrollbar, BindableProperty<float> property, UnityAction<float> valueChanged = null)
        {
            property.OnValueChanged += delegate
            {
                scrollbar.value = property.Value;
                valueChanged?.Invoke(property.Value);
            };
            scrollbar.onValueChanged.AddListener((x) =>
            {
                property.Value = x;
            });
            UnityEvents.Add(scrollbar.onValueChanged);
        }

        /// <summary>绑定属性</summary>
        /// <param name="dropdown">下拉框</param>
        /// <param name="property">属性</param>
        /// <param name="valueChanged">属性值改变回调</param>
        public void Bind(Dropdown dropdown, BindableProperty<int> property, UnityAction<int> valueChanged = null)
        {
            property.OnValueChanged += delegate
            {
                dropdown.value = property.Value;
                valueChanged?.Invoke(property.Value);
            };
            dropdown.onValueChanged.AddListener((x) =>
            {
                property.Value = x;
            });
            UnityEvents.Add(dropdown.onValueChanged);
        }

        /// <summary>点击方法绑定</summary>
        /// <param name="button">按钮</param>
        /// <param name="onClick">按钮点击回调</param>
        public void Bind(Button button, UnityAction onClick)
        {
            button.onClick.AddListener(delegate
            {
                UnityEngine.EventSystems.EventSystem.current.SetSelectedGameObject(null);
                onClick.Invoke();
            });
            UnityEvents.Add(button.onClick);
        }

        public override void Dispose()
        {
            base.Dispose();
            for (int i = 0; i < UnityEvents.Count; i++)
            {
                UnityEvents[i].RemoveAllListeners();
            }
            UnityEvents.Clear();
            for (int i = 0; i < Propertys.Count; i++)
            {
                Propertys[i].Dispose();
            }
            Propertys.Clear();
        }
    }
}