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

namespace InABox.Core
{
    public delegate void QAFormDocumentsLoadedHandler(IQAFormDocumentDataModel model);

    public delegate void StartedEventHandler();

    public interface IQAFormDocumentDataModel
    {
        List<Document> Documents { get; }
        List<IEntityDocument> DocumentLinks { get; }
        event QAFormDocumentsLoadedHandler OnDocumentsLoaded;
    }

    public class DigitalFormDocumentDataModel<TEntity, TEntityLink, TInstance, TDocument> : DigitalFormDataModel<TEntity, TEntityLink, TInstance>,
        IQAFormDocumentDataModel
        where TEntity : Entity, IRemotable, IPersistent, new()
        where TEntityLink : EntityLink<TEntity>
        where TInstance : Entity, IRemotable, IPersistent, IDigitalFormInstance<TEntityLink>, new()
        where TDocument : Entity, IRemotable, IPersistent, IEntityDocument, new()

    {
        public DigitalFormDocumentDataModel(Guid entityid, Guid instanceid, DigitalFormVariable[] variables) : base(entityid, instanceid, variables)
        {
            Documents = new List<Document>();
            DocumentLinks = new List<IEntityDocument>();
        }

        public List<Document> Documents { get; }

        public List<IEntityDocument> DocumentLinks { get; }

        public event QAFormDocumentsLoadedHandler? OnDocumentsLoaded;


        public override void AddQueries(MultiQuery client)
        {
            base.AddQueries(client);
            client.Add(
                new QueryDef<TDocument>(
                    new Filter<TDocument>("EntityLink.ID").IsEqualTo(Entity.ID),
                    null,
                    null
                ),
                typeof(TDocument)
            );
        }

        public override void ParseQueries(MultiQuery client)
        {
            base.ParseQueries(client);
            if (client.Contains(typeof(TDocument)))
            {
                DocumentLinks.AddRange(client.Get(typeof(TDocument)).Rows.Select(x => x.ToObject<TDocument>()));
                var docids = DocumentLinks.Select(x => x.DocumentLink.ID).ToArray();
                new Client<Document>().Query(
                    new Filter<Document>(x => x.ID).InList(docids),
                    null,
                    null,
                    CoreRange.All,
                    (table, error) =>
                    {
                        if (table != null)
                        {
                            foreach (var row in table.Rows)
                                Documents.Add(row.ToObject<Document>());
                            OnDocumentsLoaded?.Invoke(this);
                        }
                        else if(error != null)
                        {
                            Logger.Send(LogType.Error, "", CoreUtils.FormatException(error));
                        }
                    }
                );
            }
        }

        protected override void AddPrimaryUpdates(MultiSave client)
        {
            base.AddPrimaryUpdates(client);
            foreach (var doc in Documents.Where(x => x.ID.Equals(Guid.Empty)))
                client.Add(typeof(Document), doc);
        }

        protected override void AddSecondaryUpdates(MultiSave client)
        {
            base.AddSecondaryUpdates(client);

            foreach (var doc in Documents)
                if (!DocumentLinks.Any(x => x.DocumentLink.ID.Equals(doc.ID)))
                {
                    var link = new TDocument();
                    link.DocumentLink.ID = doc.ID;
                    DocumentLinks.Add(link);
                }

            foreach (var link in DocumentLinks)
            {
                CoreUtils.SetPropertyValue(link, "EntityLink.ID", Entity.ID);
                if (link.IsChanged())
                    client.Add(typeof(TDocument), (Entity)link);
            }
        }
    }
}