using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Domain.Time;
using NPP.SmartSchedue.Api.Core.Repositories;
using ZhonTai.Admin.Core.Db;
using ZhonTai.Admin.Core.Db.Transaction;
using ZhonTai.Admin.Core.Repositories;

namespace NPP.SmartSchedue.Api.Repositories.Time;

/// <summary>
/// 班次不可用标记仓储实现
/// 提供高性能的班次不可用数据访问方法
/// </summary>
public class ShiftUnavailabilityRepository : AppRepositoryBase<ShiftUnavailabilityEntity>, IShiftUnavailabilityRepository
{
    public ShiftUnavailabilityRepository(UnitOfWorkManagerCloud muowm) : base(muowm)
    {
    }

    /// <summary>
    /// 获取指定员工在指定日期范围内的不可用记录
    /// 用于网格视图数据加载，一次性获取整月数据避免N+1查询
    /// </summary>
    public async Task<List<ShiftUnavailabilityEntity>> GetByPersonnelAndDateRangeAsync(long personnelId, DateTime startDate, DateTime endDate)
    {
        return await Select
            .Where(x => x.PersonnelId == personnelId && 
                       x.Date >= startDate.Date && 
                       x.Date <= endDate.Date)
            .OrderBy(x => x.Date)
            .OrderBy(x => x.ShiftId)
            .ToListAsync();
    }

    /// <summary>
    /// 获取指定日期和班次的不可用员工ID列表
    /// 用于智能排班算法过滤不可用人员
    /// </summary>
    public async Task<List<long>> GetUnavailablePersonnelIdsAsync(DateTime date, long shiftId)
    {
        return await Select
            .Where(x => x.Date.Date == date.Date && x.ShiftId == shiftId)
            .GroupBy(x => x.PersonnelId) // 按员工分组，处理同一员工多条记录的情况
            .ToListAsync(x => x.Key); // 只返回员工ID
    }
    
    /// <summary>
    /// 检查人员班次的意愿
    /// </summary>
    /// <param name="date"></param>
    /// <param name="shiftId"></param>
    /// <param name="personnelId"></param>
    /// <returns></returns>
    public async Task<bool> CheckUnavailablePersonnelByShiftAsync(DateTime date, long shiftId, long personnelId)
    {
        return await Select
            .AnyAsync(x => x.Date.Date == date.Date && x.ShiftId == shiftId && x.PersonnelId == personnelId );
    }

    /// <summary>
    /// 获取指定日期所有班次的不可用员工分布
    /// 用于某日的批量人员可用性查询
    /// </summary>
    public async Task<Dictionary<long, List<long>>> GetDailyUnavailablePersonnelAsync(DateTime date)
    {
        var records = await Select
            .Where(x => x.Date.Date == date.Date)
            .GroupBy(x => new { x.ShiftId, x.PersonnelId })
            .ToListAsync(x => new { x.Key.ShiftId, x.Key.PersonnelId });

        return records
            .GroupBy(x => x.ShiftId)
            .ToDictionary(
                g => g.Key,
                g => g.Select(x => x.PersonnelId).ToList()
            );
    }

    /// <summary>
    /// 批量获取日期范围内的不可用员工分布
    /// 用于智能排班算法的批量优化查询
    /// </summary>
    public async Task<Dictionary<DateTime, Dictionary<long, List<long>>>> GetRangeUnavailablePersonnelAsync(DateTime startDate, DateTime endDate)
    {
        var records = await Select
            .Where(x => x.Date >= startDate.Date && x.Date <= endDate.Date)
            .GroupBy(x => new { x.Date, x.ShiftId, x.PersonnelId })
            .ToListAsync(x => new { x.Key.Date, x.Key.ShiftId, x.Key.PersonnelId });

        return records
            .GroupBy(x => x.Date.Date)
            .ToDictionary(
                dateGroup => dateGroup.Key,
                dateGroup => dateGroup
                    .GroupBy(x => x.ShiftId)
                    .ToDictionary(
                        shiftGroup => shiftGroup.Key,
                        shiftGroup => shiftGroup.Select(x => x.PersonnelId).ToList()
                    )
            );
    }

    /// <summary>
    /// 检查指定员工在指定日期和班次是否已有不可用记录
    /// 用于避免重复插入和批量操作中的冲突检测
    /// </summary>
    public async Task<bool> ExistsAsync(long personnelId, DateTime date, long shiftId)
    {
        return await Select
            .Where(x => x.PersonnelId == personnelId && 
                       x.Date.Date == date.Date && 
                       x.ShiftId == shiftId)
            .AnyAsync();
    }

    /// <summary>
    /// 删除指定条件的记录
    /// 用于批量操作中的覆盖模式和数据清理
    /// </summary>
    public async Task<int> DeleteByConditionAsync(long personnelId, DateTime date, long? shiftId = null)
    {
        var query = Orm.Delete<ShiftUnavailabilityEntity>()
            .Where(x => x.PersonnelId == personnelId && x.Date.Date == date.Date);

        if (shiftId.HasValue)
        {
            query = query.Where(x => x.ShiftId == shiftId.Value);
        }

        return await query.ExecuteAffrowsAsync();
    }

    /// <summary>
    /// 获取统计信息
    /// 按原因类型统计指定员工在指定日期范围内的不可用次数
    /// </summary>
    public async Task<Dictionary<int, int>> GetStatisticsAsync(long personnelId, DateTime startDate, DateTime endDate)
    {
        var results = await Select
            .Where(x => x.PersonnelId == personnelId && 
                       x.Date >= startDate.Date && 
                       x.Date <= endDate.Date)
            .GroupBy(x => x.ReasonType)
            .ToListAsync(x => new { ReasonType = x.Key, Count = x.Count() });

        return results.ToDictionary(x => x.ReasonType, x => x.Count);
    }
}