using System;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using detect.gui.Context;

namespace detect.gui.Services;

public class ServiceBase<S, T> where S : new() where T : class
{
    private static S? _instance;

    public static S Instance()
    {
        return _instance ??= new S();
    }
    
    protected readonly DetectContext? Context = new DetectContext();
    
    protected T Add(T entity)
    {
        Context!.Set<T>().Add(entity);
        Context!.SaveChanges();        
        Context!.Entry(entity).State = EntityState.Detached;
        return entity;
    }

    public int Count(Expression<Func<T, bool>> predicate)
    {
        return Context!.Set<T>().Count(predicate);
    }

    protected bool Update(T entity)
    {
        Context!.Set<T>().Update(entity);
        var r = Context!.SaveChanges() > 0;
        Context!.Entry(entity).State = EntityState.Detached;
        return r;
    }

    protected bool Delete(T entity)
    {
        Context!.Set<T>().Remove(entity);
        var r = Context!.SaveChanges() > 0;
        Context!.Entry(entity).State = EntityState.Detached;
        return r;
    }

    protected void Delete(Expression<Func<T, bool>> whereLambda)
    {
        var items = Context!.Set<T>().Where(whereLambda).ToList();
        foreach (var item in items)
        {
            Delete(item);
        }
    }
    
    public bool Exist(Expression<Func<T, bool>> whereLambda)
    {
        return Context!.Set<T>().Any(whereLambda);
    }

    protected T? Find(Expression<Func<T, bool>> whereLambda)
    {
        var entity = Context!.Set<T>().AsNoTracking().FirstOrDefault(whereLambda);
        return entity;
    }

    protected IQueryable<T> FindList(Expression<Func<T, bool>> whereLambda, string orderName, bool isAsc)
    {
        var items = Context!.Set<T>().Where(whereLambda);
        items = OrderBy(items, orderName, isAsc).AsNoTracking();
        return items;
    }

    protected IQueryable<T> FindPageList(int pageIndex, int pageSize, out int totalRecord,
        Expression<Func<T, bool>> whereLambda, string orderName, bool isAsc)
    {
        var items = Context!.Set<T>().Where(whereLambda);
        totalRecord = items.Count();
        items = OrderBy(items, orderName, isAsc).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsNoTracking();
        return items;
    }

    /// <summary>
    /// 排序
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    /// <param name="source">原IQueryable</param>
    /// <param name="propertyName">排序属性名</param>
    /// <param name="isAsc">是否正序</param>
    /// <returns>排序后的IQueryable</returns>
    private static IQueryable<T> OrderBy(IQueryable<T> source, string propertyName, bool isAsc)
    {
        if (source == null)
            throw new ArgumentNullException(nameof(source), "不能为空");
        if (string.IsNullOrEmpty(propertyName))
            return source;
        var parameter = Expression.Parameter(source.ElementType);
        var property = Expression.Property(parameter, propertyName);
        if (property == null)
            throw new ArgumentNullException(nameof(propertyName), "属性不存在");
        var lambda = Expression.Lambda(property, parameter);
        var methodName = isAsc ? "OrderBy" : "OrderByDescending";
        var resultExpression = Expression.Call(typeof(Queryable), methodName,
            new[] { source.ElementType, property.Type }, source.Expression, Expression.Quote(lambda));
        return source.Provider.CreateQuery<T>(resultExpression);
    }
}