using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace CloudBuilder.Core.DatabaseAccessor.Entity
{
    /// <summary>
    /// 定义实体仓储模型的数据标准操作
    /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <typeparam name="TKey">主键类型</typeparam>
    public interface IRepository<TEntity>
        where TEntity : class
    {
        /// <summary>
        /// 实体集合
        /// </summary>
        DbSet<TEntity> Entities { get; }

        /// <summary>
        /// 不跟踪的（脱轨）实体
        /// </summary>
        IQueryable<TEntity> DetachedEntities { get; }

        /// <summary>
        /// 服务提供器
        /// </summary>
        IServiceProvider ServiceProvider { get; }
        /// <summary>
        /// 事务
        /// </summary>
        IUnitOfWork UnitOfWork { get; set; }

        DbContext GetDbContext();

        K GetRepository<K>();
        /// <summary>
        /// 动态改变主数据库
        /// </summary>
        void ChangeMasterDatabase();

        /// <summary>
        /// 动态改变主数据库
        /// </summary>
        void ChangeSecondaryDatabase();

        #region FromSqlRaw
        IQueryable<TEntity> FromSql(string sql, params object[] parameters);
        IQueryable<TEntity> FromSqlWhere(TEntity t, string where, params object[] parameters);

        TEntity[] FindBySql(string sql, params object[] parameters);
        TEntity[] FindBySqlWhere(TEntity t, string where, params object[] parameters);

        void PackSqlParameter(List<object> parameters, string parameterName, object value);

        void ExecuteNonQuery(string sql, params object[] parameters);

        object ExecuteScalar(string sql, params object[] parameters);

        DataTable SelectDataTable(string sql, params object[] parameters);

        #endregion


        #region Insert

        EntityEntry<TEntity> Insert(TEntity entity);

        void Insert(params TEntity[] entities);

        void Insert(IEnumerable<TEntity> entities);

        Task<EntityEntry<TEntity>> InsertAsync(TEntity entity, CancellationToken cancellationToken = default);

        Task InsertAsync(params TEntity[] entities);

        Task InsertAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default);

        EntityEntry<TEntity> InsertNow(TEntity entity);

        void InsertNow(params TEntity[] entities);

        void InsertNow(IEnumerable<TEntity> entities);

        Task<EntityEntry<TEntity>> InsertNowAsync(TEntity entity, CancellationToken cancellationToken = default);

        Task InsertNowAsync(params TEntity[] entities);

        Task InsertNowAsync(TEntity[] entities, CancellationToken cancellationToken = default);

        Task InsertNowAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default);
        int SaveNow();

        Task<int> SaveNowAsync(CancellationToken cancellationToken = default);

        #endregion

        #region Update
        EntityEntry<TEntity> Update(TEntity entity);
        void Update(params TEntity[] entities);
        void Update(IEnumerable<TEntity> entities);
        Task<EntityEntry<TEntity>> UpdateAsync(TEntity entity);
        Task UpdateAsync(params TEntity[] entities);
        Task UpdateAsync(IEnumerable<TEntity> entities);
        EntityEntry<TEntity> UpdateNow(TEntity entity);
        void UpdateNow(params TEntity[] entities);
        void UpdateNow(IEnumerable<TEntity> entities);
        Task<EntityEntry<TEntity>> UpdateNowAsync(TEntity entity, CancellationToken cancellationToken = default);
        Task UpdateNowAsync(params TEntity[] entities);
        Task UpdateNowAsync(TEntity[] entities, CancellationToken cancellationToken = default);
        Task UpdateNowAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default);
        EntityEntry<TEntity> UpdateInclude(TEntity entity, IEnumerable<string> propertyNames);
        EntityEntry<TEntity> UpdateInclude(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates);
        Task<EntityEntry<TEntity>> UpdateIncludeAsync(TEntity entity, string[] propertyNames);
        Task<EntityEntry<TEntity>> UpdateIncludeAsync(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates);
        Task<EntityEntry<TEntity>> UpdateIncludeAsync(TEntity entity, IEnumerable<string> propertyNames);
        Task<EntityEntry<TEntity>> UpdateIncludeAsync(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates);
        EntityEntry<TEntity> UpdateIncludeNow(TEntity entity, string[] propertyNames);
        EntityEntry<TEntity> UpdateIncludeNow(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates);
        EntityEntry<TEntity> UpdateIncludeNow(TEntity entity, IEnumerable<string> propertyNames);
        EntityEntry<TEntity> UpdateIncludeNow(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates);
        Task<EntityEntry<TEntity>> UpdateIncludeNowAsync(TEntity entity, string[] propertyNames, CancellationToken cancellationToken = default);
        Task<EntityEntry<TEntity>> UpdateIncludeNowAsync(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates, CancellationToken cancellationToken = default);
        Task<EntityEntry<TEntity>> UpdateIncludeNowAsync(TEntity entity, IEnumerable<string> propertyNames, CancellationToken cancellationToken = default);
        Task<EntityEntry<TEntity>> UpdateIncludeNowAsync(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates, CancellationToken cancellationToken = default);
        EntityEntry<TEntity> UpdateExclude(TEntity entity, IEnumerable<string> propertyNames);
        EntityEntry<TEntity> UpdateExclude(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates);
        Task<EntityEntry<TEntity>> UpdateExcludeAsync(TEntity entity, string[] propertyNames);
        Task<EntityEntry<TEntity>> UpdateExcludeAsync(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates);
        Task<EntityEntry<TEntity>> UpdateExcludeAsync(TEntity entity, IEnumerable<string> propertyNames);
        Task<EntityEntry<TEntity>> UpdateExcludeAsync(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates);
        EntityEntry<TEntity> UpdateExcludeNow(TEntity entity, string[] propertyNames);
        EntityEntry<TEntity> UpdateExcludeNow(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates);
        EntityEntry<TEntity> UpdateExcludeNow(TEntity entity, IEnumerable<string> propertyNames);
        EntityEntry<TEntity> UpdateExcludeNow(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates);
        Task<EntityEntry<TEntity>> UpdateExcludeNowAsync(TEntity entity, string[] propertyNames, CancellationToken cancellationToken = default);
        Task<EntityEntry<TEntity>> UpdateExcludeNowAsync(TEntity entity, Expression<Func<TEntity, object>>[] propertyPredicates, CancellationToken cancellationToken = default);
        Task<EntityEntry<TEntity>> UpdateExcludeNowAsync(TEntity entity, IEnumerable<string> propertyNames, CancellationToken cancellationToken = default);
        Task<EntityEntry<TEntity>> UpdateExcludeNowAsync(TEntity entity, IEnumerable<Expression<Func<TEntity, object>>> propertyPredicates, CancellationToken cancellationToken = default);

        #endregion

        #region Delete
        EntityEntry<TEntity> Delete(TEntity entity);
        void Delete(params TEntity[] entities);
        void Delete(IEnumerable<TEntity> entities);
        Task<EntityEntry<TEntity>> DeleteAsync(TEntity entity);
        Task DeleteAsync(params TEntity[] entities);
        Task DeleteAsync(IEnumerable<TEntity> entities);
        EntityEntry<TEntity> DeleteNow(TEntity entity);
        void DeleteNow(params TEntity[] entities);
        void DeleteNow(IEnumerable<TEntity> entities);
        Task<EntityEntry<TEntity>> DeleteNowAsync(TEntity entity, CancellationToken cancellationToken = default);
        Task DeleteNowAsync(params TEntity[] entities);
        Task DeleteNowAsync(TEntity[] entities, CancellationToken cancellationToken = default);
        Task DeleteNowAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default);

        #endregion
    }
}
