using System;
using System.Collections.Generic;
using System.Linq;
using InABox.Clients;
using JetBrains.Annotations;

namespace InABox.Core
{
    public interface IDigitalFormReportDataModel
    {
        public DigitalFormVariable[]? Variables { get; set; }
    }

    /// <summary>
    /// </summary>
    /// <typeparam name="T">
    ///     Should always be an EntityForm<,></typeparam>
    public class DigitalFormReportDataModel<T> : AutoDataModel<T>, IDigitalFormReportDataModel
        where T : Entity, IRemotable, IPersistent, IEntityForm, new()
    {

        private Guid? FormId { get; set; } = null;

        private CoreTable? FormDataTable { get; set; } = null;

        //private DigitalFormVariable[]? _variables = null;

        public DigitalFormVariable[]? Variables { get; set; }

        public DigitalFormReportDataModel(Filter<T> filter, Guid? formId = null) : base(filter)
        {
            FormId = formId;
        }

        public override string Name => "Digital Form Reports";

        protected override void CheckRequiredTables(List<string> requiredtables)
        {
            base.CheckRequiredTables(requiredtables);

            requiredtables.Add(TableName<T>());
        }

        private void LoadFormDataTable(Guid formID)
        {
            var formDataTable = new CoreTable();

            formDataTable.Columns.Add(new CoreColumn
            {
                ColumnName = "Parent.ID",
                DataType = typeof(Guid)
            });

            if(Variables is null)
                Variables = new Client<DigitalFormVariable>().Load(new Filter<DigitalFormVariable>(x => x.Form.ID).IsEqualTo(formID));
            
            foreach (var variable in Variables)
                foreach (var column in variable.GetVariableColumns())
                    formDataTable.Columns.Add(column);

            FormDataTable = formDataTable;

            AddTable(typeof(CoreTable), formDataTable, true, "Form_Data");
            LinkTable(typeof(T), "ID", typeof(CoreTable), "Parent.ID", childalias: "Form_Data");
        }

        private void LoadFormDataIntoRow(CoreRow row, Dictionary<string, object?> data)
        {
            foreach (var key in data.Keys)
            {
                if (key.Contains('.'))
                {
                    row[key] = data[key];
                }
                else
                {
                    var variable = Variables.FirstOrDefault(x => string.Equals(x.Code, key));
                    if (variable != null)
                        row[key] = variable.ParseValue(data[key]);
                }
            }
        }

        protected override void AfterLoad(IEnumerable<string> requiredtables)
        {
            base.AfterLoad(requiredtables);

            if(FormDataTable == null)
            {
                LoadFormDataTable(FormId ?? ExtractValues<T, Guid>(x => (x as IDigitalFormInstance)!.Form.ID).FirstOrDefault());
            }

            var idList = ExtractValues<T, Guid>(x => x.ID);
            var jsonLists = ExtractValues<T, string>(x => (x as IDigitalFormInstance)!.FormData, false).ToList();
            var blobLists = ExtractValues<T, string?>(x => (x as IDigitalFormInstance)!.BlobData, false).ToList();

            for(var i = 0; i < jsonLists.Count; ++i)
            {
                var json = jsonLists[i];
                var blobJSON = blobLists[i];

                var formData = DigitalForm.DeserializeFormData(json, blobJSON);

                var formRow = FormDataTable!.NewRow();
                formRow["Parent.ID"] = idList[i];
                if (formData != null) LoadFormDataIntoRow(formRow, formData);

                FormDataTable.Rows.Add(formRow);
            }

            Load(typeof(CoreTable), FormDataTable!, requiredtables, "Form_Data");
        }
    }
}