/*
<copyright file="BGDBUiElementBinderField.cs" company="BansheeGz">
    Copyright (c) 2018-2021 All Rights Reserved
</copyright>
*/

using System;
using System.Reflection;
using UnityEngine;
using UnityEngine.UIElements;

namespace BansheeGz.BGDatabase
{
    [Serializable]
    public class BGDBUiElementBinderField : BGDBUiElementBinderRowBasedA
    {
        [SerializeField] private string fieldIdString;

        private BGField field;

        public string FieldIdString => fieldIdString;


        public BGField Field
        {
            get
            {
                if (field?.Meta != null && !field.Meta.IsDeleted && !field.IsDeleted) return field;
                field = null;
                if (!IsFieldSet) return null;
                var m = Meta;
                if (m == null) return null;
                if (!BGId.TryParse(fieldIdString, out var fieldId)) return null;
                return field = m.GetField(fieldId);
            }
            set
            {
                if (value == null)
                {
                    fieldIdString = null;
                    field = null;
                }
                else
                {
                    var valueId = value.Id.ToString();
                    if (valueId == fieldIdString) return;
                    fieldIdString = valueId;
                    if (value.MetaId.ToString() != metaIdString)
                    {
                        metaIdString = value.MetaId.ToString();
                        entityIdString = null;
                        meta = value.Meta;
                        entity = null;
                    }

                    field = value;
                }
            }
        }
        private bool IsFieldSet => !string.IsNullOrEmpty(fieldIdString);

        public override object Value
        {
            get
            {
                var m = Meta;
                if (m == null) throw new Exception(IsMetaSet ? $"Can not find a meta using metaId={metaIdString}" : "Meta is not set");
                var f = Field;
                if (f == null) throw new Exception(IsFieldSet ? $"Can not find a field using metaId={metaIdString} and fieldId={fieldIdString}" : "Field is not set");
                var e = Entity;
                if (e == null) throw new Exception(IsEntitySet ? $"Can not find an entity using metaId={metaIdString} and entityId={entityIdString}" : "Entity is not set");
                return f.GetValue(e.Index);
            }
        }

        public override Type ValueType
        {
            get
            {
                try
                {
                    return Field?.ValueType;
                }
                catch
                {
                    return null;
                }
            }
        }

        public override string Title => "Field";

        public override void ReverseBind(UIDocument doc)
        {
            //check meta/entity/field (ReverseBind is probably called from Editor only- so do not care about performance)
            var value = Value;

            var element = GetElement(doc.rootVisualElement);
            var member = GetElementField(doc.rootVisualElement);
            if (member is PropertyInfo propertyInfo)
            {
                var val = propertyInfo.GetValue(element);
                Field.SetValue(Entity.Index, val);
            }
            else
            {
                var fieldInfo = (FieldInfo)member;
                var val = fieldInfo.GetValue(element);
                Field.SetValue(Entity.Index, val);
            }
        }

        protected override void MetaChanged()
        {
            fieldIdString = null;
            field = null;
        }
    }
}