using Furion.DatabaseAccessor.Extensions;
using YBEE.EQM.Core;

namespace YBEE.EQM.Application;

/// <summary>
/// 高考划线计划管理服务
/// </summary>
public class NceePlanService : INceePlanService, ITransient
{
    private readonly IRepository<NceePlan> _rep;

    public NceePlanService(IRepository<NceePlan> rep)
    {
        _rep = rep;
    }

    #region 创建更新
    /// <summary>
    /// 添加计划
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task Add(AddNceePlanInput input)
    {
        var maxPlan = await _rep.Where(t => t.SemesterId == input.SemesterId && t.GradeId == input.GradeId).OrderByDescending(t => t.Sequence).FirstOrDefaultAsync();
        short seq = maxPlan?.Sequence ?? 0;
        var item = input.Adapt<NceePlan>();
        item.Sequence = (short)(seq + 1);
        await item.InsertAsync();
    }
    /// <summary>
    /// 更新计划
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task Update(UpdateNceePlanInput input)
    {
        if (!await _rep.AnyAsync(t => t.Id == input.Id))
        {
            throw Oops.Oh(ErrorCode.E2001);
        }
        var item = input.Adapt<NceePlan>();
        await item.UpdateIncludeAsync(new[] {
            nameof(item.Name), 
            nameof(item.FullName), 
            nameof(item.ShortName), 
            nameof(item.Remark), 
            nameof(item.Config),
        });
    }
    /// <summary>
    /// 删除计划
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task Del(BaseId input)
    {
        var item = await _rep.FirstOrDefaultAsync(t => t.Id == input.Id) ?? throw Oops.Oh(ErrorCode.E2001);
        if (item.Status == ExamStatus.ACTIVE || item.Status == ExamStatus.STOPPED)
        {
            throw Oops.Oh(ErrorCode.E3001, "已使用");
        }
        await item.DeleteAsync();
    }
    #endregion

    #region 状态变更
    /// <summary>
    /// 开始监测
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task Start(BaseId input)
    {
        var item = await _rep.FirstOrDefaultAsync(t => t.Id == input.Id) ?? throw Oops.Oh(ErrorCode.E2001);
        if (item.Status != ExamStatus.READY)
        {
            throw Oops.Oh(ErrorCode.E2006);
        }
        item.Status = ExamStatus.ACTIVE;
        item.BeginTime = DateTime.Now;
        await item.UpdateIncludeAsync(new[] { nameof(item.Status), nameof(item.BeginTime) });
    }
    /// <summary>
    /// 结束监测
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task Stop(BaseId input)
    {
        var item = await _rep.FirstOrDefaultAsync(t => t.Id == input.Id) ?? throw Oops.Oh(ErrorCode.E2001);
        if (item.Status != ExamStatus.ACTIVE)
        {
            throw Oops.Oh(ErrorCode.E2006);
        }
        item.Status = ExamStatus.STOPPED;
        item.EndTime = DateTime.Now;
        await item.UpdateIncludeAsync(new[] { nameof(item.Status), nameof(item.EndTime) });
    }
    /// <summary>
    /// 取消监测
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task Cancel(BaseId input)
    {
        var item = await _rep.FirstOrDefaultAsync(t => t.Id == input.Id) ?? throw Oops.Oh(ErrorCode.E2001);
        if (item.Status == ExamStatus.ACTIVE)
        {
            throw Oops.Oh(ErrorCode.E2006);
        }
        item.Status = ExamStatus.CANCELLED;
        item.EndTime = DateTime.Now;
        await item.UpdateIncludeAsync(new[] { nameof(item.Status), nameof(item.EndTime) });
    }
    #endregion

    #region 查询统计
    /// <summary>
    /// 根据ID获取计划
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<NceePlanOutput> GetById(int id)
    {
        var item = await _rep.DetachedEntities.ProjectToType<NceePlanOutput>()
                                              .FirstOrDefaultAsync(t => t.Id == id) ?? throw Oops.Oh(ErrorCode.E2001);
        return item;
    }
    /// <summary>
    /// 分页查询计划列表
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<PageResult<NceePlanOutput>> QueryPageList(NceePlanPageInput input)
    {
        var query = GetQueryBase(input);
        var ret = await query.OrderByDescending(t => t.CreateTime).ProjectToType<NceePlanOutput>().ToADPagedListAsync(input.PageIndex, input.PageSize);
        return ret;
    }
    /// <summary>
    /// 获取我的单据状态数量
    /// </summary>
    /// <returns></returns>
    public async Task<List<StatusCount>> QueryStatusCount(NceePlanPageInput input)
    {
        var query = GetQueryBase(input);
        if (query == null)
        {
            return new List<StatusCount>();
        }

        var counts = await query.GroupBy(t => t.Status).Select(t => new StatusCount { Status = (int)t.Key, Count = t.Count() }).ToListAsync();
        return counts;
    }
    #endregion

    #region 私有方法
    /// <summary>
    /// 构建查询
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    private IQueryable<NceePlan> GetQueryBase(NceePlanPageInput input)
    {
        var name = !string.IsNullOrEmpty(input.Name?.Trim());
        var searchBeginTime = !string.IsNullOrEmpty(input.SearchBeginTime?.Trim());
        var searchEndTime = !string.IsNullOrEmpty(input.SearchEndTime?.Trim());
        var query = _rep.DetachedEntities.Where((name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%") || EF.Functions.Like(u.FullName, $"%{input.Name.Trim()}%") || EF.Functions.Like(u.ShortName, $"%{input.Name.Trim()}%")))
                                         .Where(input.SemesterId.HasValue, t => t.SemesterId == input.SemesterId)
                                         .Where(input.GradeId.HasValue, t => t.GradeId == input.GradeId)
                                         .Where(input.Status.HasValue, t => t.Status == input.Status)
                                         .Where((searchBeginTime, u => u.CreateTime >= DateTime.Parse(input.SearchBeginTime)))
                                         .Where((searchEndTime, u => u.CreateTime <= DateTime.Parse(input.SearchEndTime)));
        return query;
    }
    #endregion
}
