using System;
using System.Collections.Generic;
using System.Linq;

namespace InABox.Core
{
    public abstract class DimensionUnit : Entity, IRemotable, IPersistent, ISequenceable, IDimensionUnit
    {
        
        [UniqueCodeEditor(Visible = Visible.Default, Editable = Editable.Enabled)]
        [EditorSequence(1)]
        public virtual String Code { get; set; }
        
        [TextBoxEditor]
        [EditorSequence(2)]
        public virtual String Description { get; set; }
        
        [CheckBoxEditor]
        [EditorSequence(3)]
        public virtual bool HasQuantity { get; set; }
        
        [CheckBoxEditor]
        [EditorSequence(4)]
        public virtual bool HasLength { get; set; }
        
        [CheckBoxEditor]
        [EditorSequence(5)]
        public virtual bool HasWidth { get; set; }
        
        [CheckBoxEditor]
        [EditorSequence(6)]
        public virtual bool HasHeight { get; set; }
        
        [CheckBoxEditor]
        [EditorSequence(7)]
        public virtual bool HasWeight { get; set; }

        [ExpressionEditor(null, typeof(DimensionsExpressionModelGenerator))]
        [EditorSequence(8)]
        public virtual string Formula { get; set; }        
        
        [ExpressionEditor(null, typeof(DimensionsExpressionModelGenerator))]
        [EditorSequence(9)]
        public virtual string Format { get; set; }

        [NullEditor]
        public long Sequence { get; set; }
        
        protected override void Init()
        {
            base.Init();
            HasQuantity = false;
            HasLength = false;
            HasWidth = false;
            HasHeight = false;
            HasWeight = false;
            Formula = "1";
            Format = "\"EACH\"";
        }

        public bool Validate(List<String> errors)
        {
            bool result = true;

            var variables = new Dictionary<string, object?>()
            {
                { "Quantity", 1.00F },
                { "Length", 1.00F },
                { "Width", 1.00F },
                { "Height", 1.00F },
                { "Weight", 1.00F }
            };
            
            try
            {
                var expr = new CoreExpression(Formula);
                expr.Evaluate(variables);
                result = true;
            }
            catch (Exception e)
            {
                errors.Add($"{Code}: Formula [{Formula}] =>  {e.Message}");
                result = false;
            }
            
            try
            {
                var expr = new CoreExpression(Format);
                expr.Evaluate(variables);
                result = true;
            }
            catch (Exception e)
            {
                errors.Add($"{Code}: Format [{Format}] =>  {e.Message}");
                result = false;
            }

            return result;
        }

        private class DimensionsExpressionModelGenerator : IExpressionModelGenerator
        {
            public List<string> GetVariables(object?[] items)
            {
                var dimensionUnits = items.Select(x => x as IDimensionUnit).Where(x => x != null).Cast<IDimensionUnit>();
                var variables = new List<string>();

                if (dimensionUnits.All(x => x.HasQuantity)) variables.Add("Quantity");
                if (dimensionUnits.All(x => x.HasLength)) variables.Add("Length");
                if (dimensionUnits.All(x => x.HasWidth)) variables.Add("Width");
                if (dimensionUnits.All(x => x.HasHeight)) variables.Add("Height");
                if (dimensionUnits.All(x => x.HasWeight)) variables.Add("Weight");

                return variables;
            }
        }
    }
}