using System;
using System.Collections.Generic;
using System.Text;

namespace InABox.Core
{
    public interface IQueryProvider
    {
        bool ExcludeCustomProperties { get; set; }
        
        CoreTable Query(IFilter? filter = null, IColumns? columns = null, ISortOrder? sort = null, CoreRange? range = null);
    }

    public interface IQueryProvider<T> : IQueryProvider
    {
        CoreTable Query(Filter<T>? filter = null, Columns<T>? columns = null, SortOrder<T>? sort = null, CoreRange? range = null);

        void Query(Filter<T>? filter, Columns<T>? columns, SortOrder<T>? sort, CoreRange? range, Action<CoreTable?, Exception?> action);

        void Save(T entity, string auditNote);

        void Save(IEnumerable<T> entities, string auditNote);

        void Save(T entity, string auditnote, Action<T, Exception?> callback);
        void Save(IEnumerable<T> entities, string auditnote, Action<IEnumerable<T>, Exception?> callback);

        void Delete(T entity, string auditNote);

        void Delete(IEnumerable<T> entities, string auditNote);

        void Delete(T entity, string auditnote, Action<T, Exception?> callback);
        void Delete(IEnumerable<T> entities, string auditnote, Action<IList<T>, Exception?> callback);
    }

    public interface IQueryProviderFactory
    {

        bool ExcludeCustomProperties { get; }
        
        IQueryProvider Create(Type T);

        IQueryProvider<T> Create<T>()
            where T : BaseObject, new()
        {
            var result = (Create(typeof(T)) as IQueryProvider<T>)!;
            result.ExcludeCustomProperties = ExcludeCustomProperties;
            return result;
        }
    }

    public static class QueryProviderFactoryExtensions
    {
        public static CoreTable Query<T>(this IQueryProviderFactory factory, Filter<T>? filter = null, Columns<T>? columns = null, SortOrder<T>? sort = null, CoreRange? range = null)
            where T : BaseObject, new()
        {
            return factory.Create<T>().Query(filter, columns, sort, range);
        }

        public static void Query<T>(this IQueryProviderFactory factory, Filter<T>? filter, Columns<T>? columns, SortOrder<T>? sort, CoreRange? range, Action<CoreTable?, Exception?> action)
            where T : BaseObject, new()
        {
            factory.Create<T>().Query(filter, columns, sort, range, action);
        }

        public static void Save<T>(this IQueryProviderFactory factory, T entity, string auditNote)
            where T : BaseObject, new()
        {
            factory.Create<T>().Save(entity, auditNote);
        }

        public static void Save<T>(this IQueryProviderFactory factory, IEnumerable<T> entities, string auditNote)
            where T : BaseObject, new()
        {
            factory.Create<T>().Save(entities, auditNote);
        }

        public static void Delete<T>(this IQueryProviderFactory factory, T entity, string auditNote)
            where T : BaseObject, new()
        {
            factory.Create<T>().Delete(entity, auditNote);
        }
    }
}
