using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace InABox.Core
{
    public interface IExpressionModelGenerator
    {
        public List<string> GetVariables(object?[] items);
    }

    public delegate IEnumerable<String> GetVariables();
    
    public class ExpressionEditor : BaseEditor
    {
        /// <summary>
        /// The <see cref="IExpressionModel"/> to use for this expression; if set to null, the variables must be manually set for the editor.
        /// </summary>
        public Type? ModelType { get; set; }

        private IExpressionModelGenerator? _modelGenerator;        

        public Type? ModelGenerator { get; }

        public event GetVariables OnGetVariables;

        [DoNotSerialize]
        [JsonIgnore]
        public List<string>? VariableNames { get; set; }

        public ExpressionEditor(Type? modelType, Type? modelGenerator = null)
        {
            ModelType = modelType;
            if (modelGenerator != null)
            {
                if (!typeof(IExpressionModelGenerator).IsAssignableFrom(modelGenerator))
                {
                    throw new Exception($"Model generator must be a {nameof(IExpressionModelGenerator)}");
                }
                ModelGenerator = modelGenerator;
            }
        }

        protected override BaseEditor DoClone()
        {
            var result = new ExpressionEditor(ModelType, ModelGenerator)
            {
                VariableNames = VariableNames
            };
            result.OnGetVariables = OnGetVariables;
            return result;
        }

        public IEnumerable<String> GetVariables(object?[] items)
        {         
            if (VariableNames != null)
                return VariableNames;
            if (ModelGenerator != null)
            {
                _modelGenerator ??= (Activator.CreateInstance(ModelGenerator) as IExpressionModelGenerator)!;
                return _modelGenerator.GetVariables(items);
            }
            if (ModelType != null)
                return CoreExpression.GetModelVariables(ModelType);

            return OnGetVariables?.Invoke() ?? new String[] { };
        }


    }
}
