using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Internal;
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
using NPP.SmartSchedue.Api.Contracts.Services.Time.Output;

namespace NPP.SmartSchedue.Api.Services.Integration.Algorithms
{
    /// <summary>
    /// 班次规则校验引擎
    /// 【业务用途】：专门负责班次规则的批次感知验证，支持遗传算法和常规任务分配的规则检查
    /// 【核心功能】：整合9种班次规则验证，支持历史数据+批次上下文的双重验证模式
    /// 【架构设计】：借鉴WorkOrderService中ValidateShiftRuleWithBatchContextAsync的实现方式
    /// 【性能优化】：基于规则类型的优先级验证，缓存优化，批量验证支持
    /// </summary>
    public class ShiftRuleValidationEngine
    {
        private readonly ILogger<ShiftRuleValidationEngine> _logger;

        /// <summary>
        /// 【缓存优化】班次规则验证结果缓存
        /// Key: PersonnelId_TaskId_RuleType, Value: ValidationResult
        /// </summary>
        private readonly Dictionary<string, ShiftRuleValidationResult> _validationCache = new();

        /// <summary>
        /// 【性能监控】验证统计信息
        /// </summary>
        private readonly Dictionary<string, int> _validationStats = new();

        public ShiftRuleValidationEngine(
            ILogger<ShiftRuleValidationEngine> logger)
        {
            _logger = logger;
            _logger.LogInformation("班次规则校验引擎初始化完成，支持9种规则类型的批次感知验证，使用缓存替代班次服务");
        }

        /// <summary>
        /// 【核心验证方法】增强版批次感知班次规则验证
        /// 【业务逻辑】：整合9种班次规则的完整验证，支持历史数据+批次上下文的双重验证模式
        /// 【验证策略】：优先验证批次上下文冲突，然后结合历史数据进行完整性检查
        /// 【性能优化】：基于规则类型的优先级验证，快速识别高风险冲突
        /// 【深度思考】：该方法是遗传算法适应度计算的关键组件，必须确保验证的准确性和性能
        /// </summary>
        /// <param name="personnelId">验证的人员ID</param>
        /// <param name="currentTask">当前待验证的任务</param>
        /// <param name="batchContext">批次上下文（不包含当前任务的其他相关任务）</param>
        /// <returns>发现的班次规则冲突列表</returns>
        public async Task<List<string>> ValidateShiftRulesWithEnhancedBatchContextAsync(
            long personnelId, WorkOrderEntity currentTask, List<WorkOrderEntity> batchContext, GlobalAllocationContext context)
        {
            var conflicts = new List<string>();
            var validationStartTime = DateTime.Now;
            
            try
            {
                // 【前置检查】验证输入参数有效性
                if (!currentTask.ShiftId.HasValue)
                {
                    _logger.LogWarning("【批次感知验证跳过】任务{TaskCode}缺少班次ID", currentTask.WorkOrderCode);
                    return conflicts;
                }

                var currentTaskHash = $"{personnelId}_{currentTask.Id}_{currentTask.ShiftId}";
                
                _logger.LogDebug("【增强版班次规则验证开始】人员{PersonnelId}任务{TaskCode}({Date})班次{ShiftId}，批次上下文{BatchCount}个任务",
                    personnelId, currentTask.WorkOrderCode, currentTask.WorkOrderDate.ToString("yyyy-MM-dd"), 
                    currentTask.ShiftId, batchContext.Count);

                // 【规则验证主循环】遍历所有启用的班次规则进行验证
                var validationTasks = new List<Task<List<string>>>();
                var ruleValidationResults = new Dictionary<string, List<string>>();

                // 【并行验证优化】：对独立的规则进行并行验证以提升性能
                foreach (var ruleType in GetEnabledShiftRuleTypes(context))
                {
                    var validationTask = ValidateSpecificShiftRuleAsync(
                        ruleType, personnelId, currentTask, batchContext, context);
                    validationTasks.Add(validationTask);
                }

                // 等待所有规则验证完成
                var allRuleResults = await Task.WhenAll(validationTasks);
                
                // 【结果整合】合并所有规则的验证结果
                for (int i = 0; i < allRuleResults.Length; i++)
                {
                    var ruleType = GetEnabledShiftRuleTypes(context).ToList()[i];
                    var ruleConflicts = allRuleResults[i];
                    
                    if (ruleConflicts.Any())
                    {
                        conflicts.AddRange(ruleConflicts);
                        ruleValidationResults[ruleType] = ruleConflicts;
                    }
                }

                // 【性能统计】记录验证性能和结果统计
                var validationDuration = DateTime.Now - validationStartTime;
                UpdateValidationStatistics(currentTaskHash, conflicts.Count, validationDuration);

                _logger.LogInformation("【增强版班次规则验证完成】人员{PersonnelId}任务{TaskCode}共检查{RuleCount}种规则，发现{ConflictCount}个冲突，耗时{Duration}ms",
                    personnelId, currentTask.WorkOrderCode, GetEnabledShiftRuleTypes(context).Count(), 
                    conflicts.Count, validationDuration.TotalMilliseconds);

                // 【详细冲突日志】记录前5个具体冲突详情
                LogConflictDetails(personnelId, currentTask.WorkOrderCode, conflicts, ruleValidationResults);

                return conflicts;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "【增强版班次规则验证异常】人员{PersonnelId}任务{TaskCode}验证失败", 
                    personnelId, currentTask.WorkOrderCode);
                
                // 【异常处理】异常情况下返回通用冲突信息，确保系统稳定性
                return new List<string> { $"人员{personnelId}任务{currentTask.WorkOrderCode}班次规则验证异常: {ex.Message}" };
            }
        }

        /// <summary>
        /// 【规则验证核心】验证特定班次规则类型
        /// 【架构设计】：采用策略模式，根据规则类型分发到具体的验证方法
        /// 【业务覆盖】：支持规则3-9的完整验证覆盖
        /// </summary>
        /// <param name="ruleType">规则类型标识</param>
        /// <param name="personnelId">人员ID</param>
        /// <param name="currentTask">当前任务</param>
        /// <param name="batchContext">批次上下文</param>
        /// <returns>该规则类型的冲突列表</returns>
        private async Task<List<string>> ValidateSpecificShiftRuleAsync(
            string ruleType, long personnelId, WorkOrderEntity currentTask, List<WorkOrderEntity> batchContext, GlobalAllocationContext context)
        {
            try
            {
                // 【缓存检查】首先检查缓存中是否有该规则的验证结果
                var cacheKey = $"{personnelId}_{currentTask.Id}_{ruleType}";
                if (_validationCache.TryGetValue(cacheKey, out var cachedResult))
                {
                    _logger.LogTrace("【缓存命中】规则{RuleType}验证结果来自缓存", ruleType);
                    return cachedResult.Conflicts;
                }

                List<string> conflicts = new List<string>();

                // 【规则分发】根据规则类型分发到具体的验证逻辑
                switch (ruleType)
                {
                    case "3": // 一/二班不连续
                        conflicts = await ValidateShiftSequenceRuleWithBatchContextAsync(
                            "一/二班不连续规则", personnelId, currentTask, "一", "二", batchContext, context);
                        break;

                    case "4": // 二/三班不连续  
                        conflicts = await ValidateShiftSequenceRuleWithBatchContextAsync(
                            "二/三班不连续规则", personnelId, currentTask, "二", "三", batchContext, context);
                        break;

                    case "5": // 不能这周日/下周六连
                        conflicts = await ValidateSundayToSaturdayRuleWithBatchContextAsync(
                            "周日/周六连续规则", personnelId, currentTask, batchContext, context);
                        break;

                    case "6": // 不能本周六/本周日连
                        conflicts = await ValidateSaturdayToSundayRuleWithBatchContextAsync(
                            "周六/周日连续规则", personnelId, currentTask, batchContext, context);
                        break;

                    case "7": // 不能连续7天排班
                        conflicts = await ValidateMaxConsecutiveDaysRuleWithBatchContextAsync(
                            "连续7天排班限制规则", personnelId, currentTask, 7, batchContext, context);
                        break;

                    case "8": // 三班后一天不排班
                        conflicts = await ValidateRestAfterShiftRuleWithBatchContextAsync(
                            "三班后休息规则", personnelId, currentTask, "三", batchContext, context);
                        break;

                    case "9": // 二班后一天不排班
                        conflicts = await ValidateRestAfterShiftRuleWithBatchContextAsync(
                            "二班后休息规则", personnelId, currentTask, "二", batchContext, context);
                        break;
                    
                    case "12": // 当天最多排一个班次
                        conflicts = await ValidatePersonShiftRuleWithBatchContextAsync(
                            "一人当天只排一个班次", personnelId, currentTask, "二", batchContext, context);
                        break;

                    default:
                        // 【扩展性设计】未知规则类型记录警告但不阻止任务
                        _logger.LogWarning("【未知规则类型】规则类型{RuleType}暂未实现验证逻辑", ruleType);
                        break;
                }

                // 【缓存更新】将验证结果存入缓存
                var validationResult = new ShiftRuleValidationResult
                {
                    RuleType = ruleType,
                    PersonnelId = personnelId,
                    TaskId = currentTask.Id,
                    IsValid = !conflicts.Any(),
                    Conflicts = conflicts,
                    ValidatedAt = DateTime.Now
                };

                // 【内存管理】限制缓存大小，避免内存泄漏
                if (_validationCache.Count > 1000)
                {
                    ClearOldCacheEntries();
                }
                
                _validationCache[cacheKey] = validationResult;

                return conflicts;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "【规则验证异常】规则类型{RuleType}验证异常", ruleType);
                return new List<string> { $"规则{ruleType}验证异常: {ex.Message}" };
            }
        }

        /// <summary>
        /// 【规则实现3&4】班次连续性规则验证（一/二班不连续，二/三班不连续）
        /// 【业务逻辑】：同一人员同一天不能有冲突的班次安排
        /// 【深度思考】：需要综合考虑批次内任务和数据库历史任务，确保无遗漏
        /// 【验证范围】：批次内同日冲突 + 数据库历史同日冲突
        /// </summary>
        private async Task<List<string>> ValidateShiftSequenceRuleWithBatchContextAsync(
            string ruleName, long personnelId, WorkOrderEntity currentTask, 
            string firstShiftName, string secondShiftName, List<WorkOrderEntity> batchContext, GlobalAllocationContext context)
        {
            var conflicts = new List<string>();

            try
            {
                // 【班次信息获取】获取当前任务的班次信息
                var currentShift = context.ShiftInformationCache.Where(a => a.Id == currentTask.ShiftId).FirstOrDefault();
                if (currentShift == null)
                {
                    _logger.LogWarning("【班次规则】任务{TaskCode}的班次{ShiftId}信息不存在", 
                        currentTask.WorkOrderCode, currentTask.ShiftId);
                    return conflicts;
                }

                var currentDate = currentTask.WorkOrderDate.Date;

                // 【班次类型判断】检查当前班次是否为规则关注的班次之一
                bool currentIsFirstShift = currentShift.Name?.Contains(firstShiftName) == true;
                bool currentIsSecondShift = currentShift.Name?.Contains(secondShiftName) == true;

                if (!currentIsFirstShift && !currentIsSecondShift)
                {
                    // 当前班次不是规则关注的班次，无需验证
                    return conflicts;
                }

                _logger.LogDebug("【班次连续性检查】人员{PersonnelId}任务{TaskCode}当前为{ShiftType}，检查与{OtherShiftType}的冲突",
                    personnelId, currentTask.WorkOrderCode, 
                    currentIsFirstShift ? firstShiftName : secondShiftName,
                    currentIsFirstShift ? secondShiftName : firstShiftName);

                // 【批次内冲突检查】检查批次内同一天是否有冲突班次
                await ValidateBatchContextShiftConflicts(conflicts, ruleName, personnelId, currentTask, 
                    batchContext, currentDate, currentIsFirstShift, currentIsSecondShift, 
                    firstShiftName, secondShiftName, context);

                // 【历史数据冲突检查】检查数据库中同一天是否有冲突班次
                await ValidateHistoricalDataShiftConflicts(conflicts, ruleName, personnelId, currentTask,
                    currentDate, currentIsFirstShift, currentIsSecondShift, 
                    firstShiftName, secondShiftName, context);

                return conflicts;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "【班次连续性规则验证异常】规则{RuleName}", ruleName);
                return new List<string> { $"{ruleName}验证异常: {ex.Message}" };
            }
        }

        /// <summary>
        /// 【批次内冲突检查】验证批次上下文中的班次冲突
        /// </summary>
        private async Task ValidateBatchContextShiftConflicts(
            List<string> conflicts, string ruleName, long personnelId, WorkOrderEntity currentTask,
            List<WorkOrderEntity> batchContext, DateTime currentDate, 
            bool currentIsFirstShift, bool currentIsSecondShift,
            string firstShiftName, string secondShiftName, GlobalAllocationContext context)
        {
            // 获取批次内同一天同一人员的其他任务
            var batchSameDayTasks = batchContext
                .Where(wo => wo.AssignedPersonnelId == personnelId)
                .Where(wo => wo.WorkOrderDate.Date == currentDate)
                .ToList();

            foreach (var batchTask in batchSameDayTasks)
            {
                if (batchTask.ShiftId.HasValue)
                {
                    var batchShift = context.ShiftInformationCache.Where(a => a.Id == batchTask.ShiftId.Value)
                        .FirstOrDefault();
                    if (batchShift == null) continue;

                    bool batchIsFirstShift = batchShift.Name?.Contains(firstShiftName) == true;
                    bool batchIsSecondShift = batchShift.Name?.Contains(secondShiftName) == true;

                    // 【冲突检测】检查班次冲突：当前是一班且批次内有二班，或当前是二班且批次内有一班
                    if ((currentIsFirstShift && batchIsSecondShift) || (currentIsSecondShift && batchIsFirstShift))
                    {
                        var conflictMessage = $"违反批次内{ruleName}: 同一天内不能同时安排{firstShiftName}班和{secondShiftName}班 " +
                                             $"(与批次内任务 '{batchTask.WorkOrderCode}' {batchShift.Name} 冲突)";
                        conflicts.Add(conflictMessage);
                        
                        _logger.LogError("【批次内班次冲突】{Conflict}", conflictMessage);
                    }
                }
            }
        }

        /// <summary>
        /// 【历史数据冲突检查】验证历史数据中的班次冲突
        /// </summary>
        private async Task ValidateHistoricalDataShiftConflicts(
            List<string> conflicts, string ruleName, long personnelId, WorkOrderEntity currentTask,
            DateTime currentDate, bool currentIsFirstShift, bool currentIsSecondShift,
            string firstShiftName, string secondShiftName, GlobalAllocationContext context)
        {
            // 【历史数据查询优化】：使用上下文中的任务数据而非直接数据库查询
            var historicalSameDayTasks = context.Tasks?.Where(wo => 
                wo.AssignedPersonnelId == personnelId &&
                wo.Id != currentTask.Id &&
                wo.WorkOrderDate.Date == currentDate).ToList() ?? new List<WorkOrderEntity>();

            foreach (var dbTask in historicalSameDayTasks)
            {
                if (dbTask.ShiftId.HasValue)
                {
                    var dbShift = context.ShiftInformationCache.Where(a => a.Id == dbTask.ShiftId.Value)
                        .FirstOrDefault();
                    if (dbShift == null) continue;

                    bool dbIsFirstShift = dbShift.Name?.Contains(firstShiftName) == true;
                    bool dbIsSecondShift = dbShift.Name?.Contains(secondShiftName) == true;

                    // 【历史冲突检测】检查与历史数据的班次冲突
                    if ((currentIsFirstShift && dbIsSecondShift) || (currentIsSecondShift && dbIsFirstShift))
                    {
                        var conflictMessage = $"违反{ruleName}: 同一天内不能同时安排{firstShiftName}班和{secondShiftName}班 " +
                                             $"(与历史任务 '{dbTask.WorkOrderCode}' {dbShift.Name} 冲突)";
                        conflicts.Add(conflictMessage);
                        
                        _logger.LogError("【历史数据班次冲突】{Conflict}", conflictMessage);
                    }
                }
            }
        }

        /// <summary>
        /// 【规则实现5】周日/下周六连续规则验证
        /// 【业务逻辑】：防止跨周连续工作，检查周日->下周六的7天跨度
        /// 【深度思考】：批次内可能同时包含这两个时间点的任务，需要双向检查
        /// </summary>
        private async Task<List<string>> ValidateSundayToSaturdayRuleWithBatchContextAsync(
            string ruleName, long personnelId, WorkOrderEntity currentTask, List<WorkOrderEntity> batchContext, GlobalAllocationContext context)
        {
            var conflicts = new List<string>();
            await Task.CompletedTask;

            try
            {
                var currentDate = currentTask.WorkOrderDate.Date;

                // 【情况1】当前任务是周日，检查下周六是否有排班
                if (currentDate.DayOfWeek == DayOfWeek.Sunday)
                {
                    var nextSaturday = currentDate.AddDays(6); // 周日 + 6天 = 下周六
                    await CheckNextSaturdayConflicts(conflicts, ruleName, personnelId, currentTask, 
                        batchContext, nextSaturday, context);
                }

                // 【情况2】当前任务是周六，检查上周日是否有排班
                if (currentDate.DayOfWeek == DayOfWeek.Saturday)
                {
                    var lastSunday = currentDate.AddDays(-6); // 周六 - 6天 = 上周日
                    await CheckLastSundayConflicts(conflicts, ruleName, personnelId, currentTask, 
                        batchContext, lastSunday, context);
                }

                return conflicts;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "【周日/周六连续规则验证异常】规则{RuleName}", ruleName);
                return new List<string> { $"{ruleName}验证异常: {ex.Message}" };
            }
        }

        /// <summary>
        /// 【规则实现6】周六/周日连续规则验证
        /// 【业务逻辑】：防止周末连续工作，批次内可能同时包含同一人员的周六和周日任务
        /// </summary>
        private async Task<List<string>> ValidateSaturdayToSundayRuleWithBatchContextAsync(
            string ruleName, long personnelId, WorkOrderEntity currentTask, List<WorkOrderEntity> batchContext, GlobalAllocationContext context)
        {
            var conflicts = new List<string>();
            await Task.CompletedTask;

            try
            {
                var currentDate = currentTask.WorkOrderDate.Date;

                // 【情况1】当前是周六，检查周日是否有排班
                if (currentDate.DayOfWeek == DayOfWeek.Saturday)
                {
                    var sunday = currentDate.AddDays(1);
                    await CheckAdjacentDayConflicts(conflicts, ruleName, personnelId, currentTask, 
                        batchContext, sunday, "周六", "周日", context);
                }

                // 【情况2】当前是周日，检查周六是否有排班
                if (currentDate.DayOfWeek == DayOfWeek.Sunday)
                {
                    var saturday = currentDate.AddDays(-1);
                    await CheckAdjacentDayConflicts(conflicts, ruleName, personnelId, currentTask, 
                        batchContext, saturday, "周日", "周六", context);
                }

                return conflicts;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "【周六/周日连续规则验证异常】规则{RuleName}", ruleName);
                return new List<string> { $"{ruleName}验证异常: {ex.Message}" };
            }
        }

        /// <summary>
        /// 【规则实现7】最大连续天数规则验证
        /// 【业务逻辑】：最严格的连续工作限制，基于批次+历史数据计算真实的连续工作天数序列
        /// </summary>
        private async Task<List<string>> ValidateMaxConsecutiveDaysRuleWithBatchContextAsync(
            string ruleName, long personnelId, WorkOrderEntity currentTask, int maxDays, 
            List<WorkOrderEntity> batchContext, GlobalAllocationContext context)
        {
            var conflicts = new List<string>();

            try
            {
                // 【连续天数计算】使用批次感知的连续工作天数计算
                var consecutiveDays = await CalculateConsecutiveWorkDaysWithBatchContextAsync(
                    personnelId, currentTask.WorkOrderDate, batchContext, context);

                if (consecutiveDays >= maxDays)
                {
                    // 【相关任务信息】获取相关的批次内任务信息用于详细说明
                    var relatedBatchTasks = batchContext
                        .Where(wo => wo.AssignedPersonnelId == personnelId)
                        .Where(wo => Math.Abs((wo.WorkOrderDate.Date - currentTask.WorkOrderDate.Date).Days) <= maxDays)
                        .Select(wo => wo.WorkOrderCode)
                        .ToList();

                    var batchTasksInfo = relatedBatchTasks.Any() ? 
                        $"（涉及批次内任务: {string.Join(", ", relatedBatchTasks)}）" : "";

                    var conflictMessage = $"违反{ruleName}: 连续工作 {consecutiveDays} 天超过限制 {maxDays} 天 {batchTasksInfo}";
                    conflicts.Add(conflictMessage);

                    _logger.LogError("【连续天数规则冲突】{Conflict}", conflictMessage);
                }

                return conflicts;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "【连续天数规则验证异常】规则{RuleName}", ruleName);
                return new List<string> { $"{ruleName}验证异常: {ex.Message}" };
            }
        }

        /// <summary>
        /// 【规则实现8&9】班次后休息规则验证（二班后休息，三班后休息）
        /// 【业务逻辑】：指定班次后次日必须休息，需要双向检查前一天和后一天
        /// </summary>
        private async Task<List<string>> ValidateRestAfterShiftRuleWithBatchContextAsync(
            string ruleName, long personnelId, WorkOrderEntity currentTask, string shiftName, 
            List<WorkOrderEntity> batchContext, GlobalAllocationContext context)
        {
            var conflicts = new List<string>();

            try
            {
                var currentDate = currentTask.WorkOrderDate.Date;

                // 【双向检查1】检查前一天是否是指定班次
                await CheckPreviousDayRestRule(conflicts, ruleName, personnelId, currentTask, 
                    batchContext, shiftName, currentDate, context);

                // 【双向检查2】检查当前是指定班次时后一天是否安排了工作
                await CheckNextDayRestRule(conflicts, ruleName, personnelId, currentTask, 
                    batchContext, shiftName, currentDate, context);

                return conflicts;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "【班次后休息规则验证异常】规则{RuleName}", ruleName);
                return new List<string> { $"{ruleName}验证异常: {ex.Message}" };
            }
        }
        
        private async Task<List<string>> ValidatePersonShiftRuleWithBatchContextAsync(
            string ruleName, long personnelId, WorkOrderEntity currentTask, string shiftName, 
            List<WorkOrderEntity> batchContext, GlobalAllocationContext context)
        {
            var conflicts = new List<string>();

            try
            {
                var currentDate = currentTask.WorkOrderDate.Date;
                
                var batchNextTask = batchContext
                    .Where(wo => wo.AssignedPersonnelId == personnelId)
                    .Where(wo => wo.WorkOrderDate.Date == currentDate)
                    .Count();

                if (batchNextTask > 1)
                {
                    var conflictMessage = $"违反批次内{ruleName}";
                    conflicts.Add(conflictMessage);
                    _logger.LogError("【批次内安排冲突】{Conflict}", conflictMessage);
                }
                
                return conflicts;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "【班次后休息规则验证异常】规则{RuleName}", ruleName);
                return new List<string> { $"{ruleName}验证异常: {ex.Message}" };
            }
        }

        /// <summary>
        /// 【辅助方法】检查前一天的休息规则
        /// </summary>
        private async Task CheckPreviousDayRestRule(List<string> conflicts, string ruleName, 
            long personnelId, WorkOrderEntity currentTask, List<WorkOrderEntity> batchContext, 
            string shiftName, DateTime currentDate, GlobalAllocationContext context)
        {
            var previousDay = currentDate.AddDays(-1);

            // 【批次内检查】先检查批次内是否有前一天的指定班次任务
            var batchPreviousTask = batchContext
                .Where(wo => wo.AssignedPersonnelId == personnelId)
                .Where(wo => wo.WorkOrderDate.Date == previousDay)
                .FirstOrDefault();

            if (batchPreviousTask?.ShiftId.HasValue == true)
            {
                var batchPreviousShift = context.ShiftInformationCache.Where(a => a.Id == batchPreviousTask.ShiftId.Value)
                    .FirstOrDefault();
                if (batchPreviousShift?.Name?.Contains(shiftName) == true)
                {
                    var conflictMessage = $"违反批次内{ruleName}: 批次内任务 '{batchPreviousTask.WorkOrderCode}' " +
                                         $"{shiftName}班后一天不能安排工作";
                    conflicts.Add(conflictMessage);
                    _logger.LogError("【批次内休息规则冲突】{Conflict}", conflictMessage);
                }
            }
            else
            {
                // 【历史数据检查】检查历史数据中前一天是否有指定班次
                await CheckHistoricalPreviousDayTask(conflicts, ruleName, personnelId, previousDay, shiftName, context);
            }
        }

        /// <summary>
        /// 【辅助方法】检查后一天的休息规则
        /// </summary>
        private async Task CheckNextDayRestRule(List<string> conflicts, string ruleName, 
            long personnelId, WorkOrderEntity currentTask, List<WorkOrderEntity> batchContext, 
            string shiftName, DateTime currentDate, GlobalAllocationContext context)
        {
            // 【当前任务检查】检查当前任务是否为指定班次
            var currentShift = context.ShiftInformationCache.Where(a => a.Id == (currentTask.ShiftId ?? 0))
                .FirstOrDefault();
            if (currentShift?.Name?.Contains(shiftName) == true)
            {
                var nextDay = currentDate.AddDays(1);

                // 【批次内后一天检查】检查批次内是否有后一天的任务
                var batchNextTask = batchContext
                    .Where(wo => wo.AssignedPersonnelId == personnelId)
                    .Where(wo => wo.WorkOrderDate.Date == nextDay)
                    .Any();

                if (batchNextTask)
                {
                    var conflictMessage = $"违反批次内{ruleName}: {shiftName}班后一天不能安排批次内任务";
                    conflicts.Add(conflictMessage);
                    _logger.LogError("【批次内次日安排冲突】{Conflict}", conflictMessage);
                }
                else
                {
                    // 【历史数据后一天检查】检查历史数据中是否有后一天的任务
                    await CheckHistoricalNextDayTask(conflicts, ruleName, personnelId, nextDay, shiftName, context);
                }
            }
        }

        /// <summary>
        /// 【缓存管理】清理过期的缓存条目
        /// </summary>
        private void ClearOldCacheEntries()
        {
            var cutoffTime = DateTime.Now.AddMinutes(-30); // 清理30分钟前的缓存
            var keysToRemove = _validationCache
                .Where(kvp => kvp.Value.ValidatedAt < cutoffTime)
                .Select(kvp => kvp.Key)
                .Take(200) // 每次最多清理200个
                .ToList();

            foreach (var key in keysToRemove)
            {
                _validationCache.Remove(key);
            }

            _logger.LogDebug("【缓存清理】清理了{Count}个过期的验证缓存项", keysToRemove.Count);
        }

        /// <summary>
        /// 【统计更新】更新验证统计信息
        /// </summary>
        private void UpdateValidationStatistics(string taskHash, int conflictCount, TimeSpan duration)
        {
            var statsKey = conflictCount > 0 ? "ValidationWithConflicts" : "ValidationPassed";
            _validationStats[statsKey] = _validationStats.GetValueOrDefault(statsKey, 0) + 1;
            _validationStats["TotalValidationTime"] = _validationStats.GetValueOrDefault("TotalValidationTime", 0) + (int)duration.TotalMilliseconds;
        }

        /// <summary>
        /// 【日志记录】记录冲突详情
        /// </summary>
        private void LogConflictDetails(long personnelId, string taskCode, List<string> allConflicts, Dictionary<string, List<string>> ruleResults)
        {
            if (allConflicts.Any())
            {
                _logger.LogError("【冲突汇总】人员{PersonnelId}任务{TaskCode}发现{TotalConflicts}个冲突", 
                    personnelId, taskCode, allConflicts.Count);

                // 按规则类型分组显示冲突
                foreach (var rule in ruleResults)
                {
                    _logger.LogError("【规则{RuleType}冲突】{ConflictCount}个: {Conflicts}", 
                        rule.Key, rule.Value.Count, string.Join("; ", rule.Value.Take(2)));
                }

                // 显示前5个具体冲突
                for (int i = 0; i < Math.Min(5, allConflicts.Count); i++)
                {
                    _logger.LogError("【冲突详情{Index}】{Conflict}", i + 1, allConflicts[i]);
                }
            }
        }

        /// <summary>
        /// 【配置方法】获取启用的班次规则类型列表
        /// </summary>
        private IEnumerable<string> GetEnabledShiftRuleTypes(GlobalAllocationContext context)
        {
            return context.ShiftRulesMapping.OrderBy(a => a.RuleType).Where(a=> a.IsEnabled == true).Select(a => a.RuleType).ToArray();
        }
        
        /// <summary>
        /// 【辅助方法】检查下周六冲突 - 周日/下周六连续规则的核心逻辑
        /// </summary>
        private async Task CheckNextSaturdayConflicts(List<string> conflicts, string ruleName, 
            long personnelId, WorkOrderEntity currentTask, List<WorkOrderEntity> batchContext, DateTime nextSaturday, GlobalAllocationContext context)
        {
            // 【批次内检查】先检查批次内是否有下周六的任务
            var batchNextSaturday = batchContext
                .Where(wo => wo.AssignedPersonnelId == personnelId)
                .Where(wo => wo.WorkOrderDate.Date == nextSaturday)
                .FirstOrDefault();

            if (batchNextSaturday != null)
            {
                var conflictMessage = $"违反批次内{ruleName}: 不能在这周日和下周六安排工作 " +
                                     $"(与批次内任务 '{batchNextSaturday.WorkOrderCode}' 冲突)";
                conflicts.Add(conflictMessage);
                _logger.LogError("【批次内跨周冲突】{Conflict}", conflictMessage);
            }
            else
            {
                // 【历史数据检查】检查历史数据中下周六是否有任务
                var dbNextSaturday = context.Tasks?.Any(wo => 
                    wo.AssignedPersonnelId == personnelId &&
                    wo.WorkOrderDate.Date == nextSaturday) == true;

                if (dbNextSaturday)
                {
                    var conflictMessage = $"违反{ruleName}: 不能在这周日和下周六安排工作 (与历史数据任务冲突)";
                    conflicts.Add(conflictMessage);
                    _logger.LogError("【历史数据跨周冲突】{Conflict}", conflictMessage);
                }
            }

            await Task.CompletedTask;
        }

        /// <summary>
        /// 【辅助方法】检查上周日冲突 - 周日/下周六连续规则的反向逻辑
        /// </summary>
        private async Task CheckLastSundayConflicts(List<string> conflicts, string ruleName, 
            long personnelId, WorkOrderEntity currentTask, List<WorkOrderEntity> batchContext, DateTime lastSunday, GlobalAllocationContext context)
        {
            // 【批次内检查】先检查批次内是否有上周日的任务
            var batchLastSunday = batchContext
                .Where(wo => wo.AssignedPersonnelId == personnelId)
                .Where(wo => wo.WorkOrderDate.Date == lastSunday)
                .FirstOrDefault();

            if (batchLastSunday != null)
            {
                var conflictMessage = $"违反批次内{ruleName}: 不能在上周日和这周六安排工作 " +
                                     $"(与批次内任务 '{batchLastSunday.WorkOrderCode}' 冲突)";
                conflicts.Add(conflictMessage);
                _logger.LogError("【批次内反向跨周冲突】{Conflict}", conflictMessage);
            }
            else
            {
                // 【历史数据检查】检查历史数据中上周日是否有任务
                var dbLastSunday = context.Tasks?.Any(wo => 
                    wo.AssignedPersonnelId == personnelId &&
                    wo.WorkOrderDate.Date == lastSunday) == true;

                if (dbLastSunday)
                {
                    var conflictMessage = $"违反{ruleName}: 不能在上周日和这周六安排工作 (与历史数据任务冲突)";
                    conflicts.Add(conflictMessage);
                    _logger.LogError("【历史数据反向跨周冲突】{Conflict}", conflictMessage);
                }
            }

            await Task.CompletedTask;
        }

        /// <summary>
        /// 【辅助方法】检查相邻日期冲突 - 周六/周日连续规则的通用逻辑
        /// </summary>
        private async Task CheckAdjacentDayConflicts(List<string> conflicts, string ruleName, 
            long personnelId, WorkOrderEntity currentTask, List<WorkOrderEntity> batchContext, 
            DateTime adjacentDay, string currentDayName, string adjacentDayName, GlobalAllocationContext context)
        {
            // 【批次内相邻日检查】先检查批次内相邻日期任务
            var batchAdjacentTask = batchContext
                .Where(wo => wo.AssignedPersonnelId == personnelId)
                .Where(wo => wo.WorkOrderDate.Date == adjacentDay)
                .FirstOrDefault();

            if (batchAdjacentTask != null)
            {
                var conflictMessage = $"违反批次内{ruleName}: 不能在{currentDayName}和{adjacentDayName}连续安排工作 " +
                                     $"(与批次内任务 '{batchAdjacentTask.WorkOrderCode}' 冲突)";
                conflicts.Add(conflictMessage);
                _logger.LogError("【批次内相邻日冲突】{Conflict}", conflictMessage);
            }
            else
            {
                // 【历史数据相邻日检查】检查历史数据中相邻日期是否有任务
                var dbAdjacentTask = context.Tasks?.Any(wo => 
                    wo.AssignedPersonnelId == personnelId &&
                    wo.WorkOrderDate.Date == adjacentDay) == true;

                if (dbAdjacentTask)
                {
                    var conflictMessage = $"违反{ruleName}: 不能在{currentDayName}和{adjacentDayName}连续安排工作 (与历史数据任务冲突)";
                    conflicts.Add(conflictMessage);
                    _logger.LogError("【历史数据相邻日冲突】{Conflict}", conflictMessage);
                }
            }

            await Task.CompletedTask;
        }

        /// <summary>
        /// 【辅助方法】检查历史数据前一天任务 - 班次后休息规则的历史数据检查
        /// </summary>
        private async Task CheckHistoricalPreviousDayTask(List<string> conflicts, string ruleName, 
            long personnelId, DateTime previousDay, string shiftName, GlobalAllocationContext context)
        {
            var dbPreviousTask = context.Tasks?.FirstOrDefault(wo => 
                wo.AssignedPersonnelId == personnelId &&
                wo.WorkOrderDate.Date == previousDay);

            if (dbPreviousTask?.ShiftId.HasValue == true)
            {
                var dbPreviousShift = context.ShiftInformationCache.Where(a => a.Id == dbPreviousTask.ShiftId.Value)
                    .FirstOrDefault();
                if (dbPreviousShift?.Name?.Contains(shiftName) == true)
                {
                    var conflictMessage = $"违反{ruleName}: 历史数据任务 '{dbPreviousTask.WorkOrderCode}' " +
                                         $"{shiftName}班后一天不能安排工作";
                    conflicts.Add(conflictMessage);
                    _logger.LogError("【历史数据前日班次冲突】{Conflict}", conflictMessage);
                }
            }
        }

        /// <summary>
        /// 【辅助方法】检查历史数据后一天任务 - 班次后休息规则的历史数据检查
        /// </summary>
        private async Task CheckHistoricalNextDayTask(List<string> conflicts, string ruleName, 
            long personnelId, DateTime nextDay, string shiftName, GlobalAllocationContext context)
        {
            var dbNextTask = context.Tasks?.Any(wo => 
                wo.AssignedPersonnelId == personnelId &&
                wo.WorkOrderDate.Date == nextDay) == true;

            if (dbNextTask)
            {
                var conflictMessage = $"违反{ruleName}: {shiftName}班后一天不能安排工作（与历史数据任务冲突）";
                conflicts.Add(conflictMessage);
                _logger.LogError("【历史数据次日安排冲突】{Conflict}", conflictMessage);
            }

            await Task.CompletedTask;
        }

        /// <summary>
        /// 【核心算法】计算批次感知的连续工作天数 - 最大连续天数规则的核心实现
        /// 【业务逻辑】：整合批次内任务和历史数据，计算真实的连续工作天数
        /// 【深度思考】：需要处理批次内任务的时序关系，确保连续性计算的准确性
        /// </summary>
        private async Task<int> CalculateConsecutiveWorkDaysWithBatchContextAsync(
            long personnelId, DateTime targetDate, List<WorkOrderEntity> batchContext, GlobalAllocationContext context)
        {
            await Task.CompletedTask;

            try
            {
                var consecutiveDays = 1; // 包含目标日期

                // 【批次任务整合】获取批次内该人员的任务，按日期排序
                var personnelBatchTasks = batchContext
                    .Where(wo => wo.AssignedPersonnelId == personnelId)
                    .OrderBy(wo => wo.WorkOrderDate.Date)
                    .ToList();

                // 【历史任务整合】获取历史上下文中该人员的任务
                var personnelHistoryTasks = context.Tasks?.Where(wo => 
                    wo.AssignedPersonnelId == personnelId &&
                    !personnelBatchTasks.Any(bt => bt.Id == wo.Id)) // 避免重复
                    .ToList() ?? new List<WorkOrderEntity>();

                // 【时序数据构建】创建包含批次任务和历史任务的完整工作日期集合
                var allWorkDates = new HashSet<DateTime>();
                
                // 添加批次内任务日期
                foreach (var task in personnelBatchTasks)
                {
                    allWorkDates.Add(task.WorkOrderDate.Date);
                }
                
                // 添加历史任务日期
                foreach (var task in personnelHistoryTasks)
                {
                    allWorkDates.Add(task.WorkOrderDate.Date);
                }
                
                // 包含当前目标日期
                allWorkDates.Add(targetDate.Date);

                // 【连续性计算】从目标日期往前检查连续工作天数
                var currentDate = targetDate.Date.AddDays(-1); // 从目标日期前一天开始往前检查

                while (true)
                {
                    // 【工作日检查】检查当前日期是否有工作安排
                    bool hasWork = allWorkDates.Contains(currentDate);

                    if (!hasWork)
                    {
                        break; // 没有工作任务，中断连续天数
                    }

                    // 【班次不可用性检查】检查是否有班次不可用情况 - 深度实现
                    var isUnavailable = CheckPersonnelShiftUnavailability(personnelId, currentDate, context);
                    
                    _logger.LogTrace("【班次不可用性检查】人员{PersonnelId}在{Date:yyyy-MM-dd}的可用状态：{IsAvailable}", 
                        personnelId, currentDate, !isUnavailable);

                    if (isUnavailable)
                    {
                        break; // 班次不可用，中断连续天数
                    }

                    consecutiveDays++;
                    currentDate = currentDate.AddDays(-1);

                    // 【安全限制】避免无限循环，最多检查60天
                    if (consecutiveDays > 60)
                    {
                        _logger.LogWarning("【连续天数计算】人员{PersonnelId}连续工作天数计算超过60天限制", personnelId);
                        break;
                    }
                }

                _logger.LogDebug("【连续天数计算完成】人员{PersonnelId}目标日期{TargetDate:yyyy-MM-dd}连续工作{ConsecutiveDays}天",
                    personnelId, targetDate, consecutiveDays);

                return consecutiveDays;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "【连续天数计算异常】人员{PersonnelId}目标日期{TargetDate}", personnelId, targetDate);
                return 1; // 异常时返回最小值，避免过度限制
            }
        }

        /// <summary>
        /// 【深度实现】检查人员在指定日期的班次不可用性
        /// 【业务思考】：整合GlobalAllocationContext中的班次不可用性缓存，支持高性能查询
        /// 【数据来源】：DateShiftUnavailablePersonnel + PersonnelUnavailabilityIndex + UnavailabilityDetails
        /// 【查询策略】：优先使用PersonnelUnavailabilityIndex进行O(1)查询，再检查详细信息
        /// 【约束类型】：区分硬约束（请假、医疗）和软约束（个人意愿、培训）
        /// </summary>
        /// <param name="personnelId">人员ID</param>
        /// <param name="checkDate">检查日期</param>
        /// <param name="context">全局分配上下文</param>
        /// <returns>是否不可用（true表示不可用，false表示可用）</returns>
        private bool CheckPersonnelShiftUnavailability(long personnelId, DateTime checkDate, GlobalAllocationContext context)
        {
            try
            {
                var targetDate = checkDate.Date;
                
                // 【查询策略1】优先使用PersonnelUnavailabilityIndex进行O(1)查询
                if (context.PersonnelUnavailabilityIndex.TryGetValue(personnelId, out var unavailabilityDates))
                {
                    // 检查该人员在目标日期是否有不可用记录
                    if (unavailabilityDates.TryGetValue(targetDate, out var unavailableShifts))
                    {
                        // 只要有任意班次不可用，就认为该日不可用（保守策略）
                        if (unavailableShifts.Any())
                        {
                            _logger.LogDebug("【班次不可用性命中】人员{PersonnelId}在{Date:yyyy-MM-dd}有{ShiftCount}个班次不可用", 
                                personnelId, checkDate, unavailableShifts.Count);
                            
                            // 【详细信息查询】获取不可用的具体原因和约束类型
                            var hardConstraintExists = CheckForHardConstraints(personnelId, targetDate, unavailableShifts, context);
                            
                            if (hardConstraintExists)
                            {
                                _logger.LogDebug("【硬约束检测】人员{PersonnelId}在{Date:yyyy-MM-dd}存在硬约束不可用情况", personnelId, checkDate);
                                return true; // 硬约束不可用
                            }
                            else
                            {
                                _logger.LogTrace("【软约束检测】人员{PersonnelId}在{Date:yyyy-MM-dd}仅有软约束不可用，可协调", personnelId, checkDate);
                                return false; // 软约束可协调，认为可用
                            }
                        }
                    }
                }
                
                // 【查询策略2】后备查询：使用DateShiftUnavailablePersonnel验证
                var fallbackUnavailable = CheckDateShiftUnavailabilityFallback(personnelId, targetDate, context);
                if (fallbackUnavailable)
                {
                    _logger.LogDebug("【后备查询命中】人员{PersonnelId}在{Date:yyyy-MM-dd}通过后备查询发现不可用", personnelId, checkDate);
                    return true;
                }
                
                // 【可用结论】所有查询都未发现不可用情况
                _logger.LogTrace("【班次可用性验证通过】人员{PersonnelId}在{Date:yyyy-MM-dd}可用", personnelId, checkDate);
                return false;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "【班次不可用性检查异常】人员{PersonnelId}日期{CheckDate:yyyy-MM-dd}", personnelId, checkDate);
                
                // 【异常处理】异常情况下保守处理，假设可用（避免过度限制）
                return false;
            }
        }

        /// <summary>
        /// 【辅助方法】检查硬约束是否存在
        /// 【业务逻辑】：通过UnavailabilityDetails查询具体的不可用原因，区分硬约束和软约束
        /// 【约束类型】：硬约束(请假、医疗)必须遵守，软约束(个人意愿、培训)可协调
        /// </summary>
        private bool CheckForHardConstraints(long personnelId, DateTime targetDate, HashSet<long> unavailableShifts, GlobalAllocationContext context)
        {
            try
            {
                // 遍历所有不可用的班次，检查是否存在硬约束
                foreach (var shiftId in unavailableShifts)
                {
                    var detailKey = $"{targetDate:yyyyMMdd}_{shiftId}_{personnelId}";
                    
                    if (context.UnavailabilityDetails.TryGetValue(detailKey, out var unavailabilityDetail))
                    {
                        // 检查是否为硬约束类型
                        if (unavailabilityDetail.IsHardConstraint)
                        {
                            _logger.LogDebug("【硬约束发现】人员{PersonnelId}日期{Date:yyyy-MM-dd}班次{ShiftId}：{ReasonType}({ConstraintScore})", 
                                personnelId, targetDate, shiftId, unavailabilityDetail.ReasonType, unavailabilityDetail.ConstraintScore);
                            return true;
                        }
                        else
                        {
                            _logger.LogTrace("【软约束检测】人员{PersonnelId}日期{Date:yyyy-MM-dd}班次{ShiftId}：{ReasonType}(可协调)", 
                                personnelId, targetDate, shiftId, unavailabilityDetail.ReasonType);
                        }
                    }
                }
                
                return false; // 未发现硬约束
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "【硬约束检查异常】人员{PersonnelId}日期{Date:yyyy-MM-dd}", personnelId, targetDate);
                return true; // 异常情况下保守处理，认为存在硬约束
            }
        }

        /// <summary>
        /// 【辅助方法】后备查询：使用DateShiftUnavailablePersonnel验证
        /// 【查询策略】：当PersonnelUnavailabilityIndex缺失时的后备验证机制
        /// 【性能考虑】：虽然性能略低于索引查询，但确保数据一致性
        /// </summary>
        private bool CheckDateShiftUnavailabilityFallback(long personnelId, DateTime targetDate, GlobalAllocationContext context)
        {
            try
            {
                // 获取该日期所有可能的班次ID（这里简化处理，实际应该从系统配置获取）
                // 为了演示，我们检查一些常见的班次ID模式
                var commonShiftIds = new[] { 1L, 2L, 3L }; // 一班、二班、三班
                
                foreach (var shiftId in commonShiftIds)
                {
                    var dateShiftKey = $"{targetDate:yyyyMMdd}_{shiftId}";
                    
                    if (context.DateShiftUnavailablePersonnel.TryGetValue(dateShiftKey, out var unavailablePersonnels))
                    {
                        if (unavailablePersonnels.Contains(personnelId))
                        {
                            _logger.LogTrace("【后备查询命中】人员{PersonnelId}在{Date:yyyy-MM-dd}班次{ShiftId}不可用", 
                                personnelId, targetDate, shiftId);
                            
                            // 进一步检查是否为硬约束
                            var detailKey = $"{dateShiftKey}_{personnelId}";
                            if (context.UnavailabilityDetails.TryGetValue(detailKey, out var detail))
                            {
                                return detail.IsHardConstraint;
                            }
                            else
                            {
                                return true; // 无详细信息时保守处理
                            }
                        }
                    }
                }
                
                return false; // 后备查询未发现不可用情况
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "【后备查询异常】人员{PersonnelId}日期{Date:yyyy-MM-dd}", personnelId, targetDate);
                return false; // 异常情况下假设可用，避免过度限制
            }
        }

        /// <summary>
        /// 【验证结果数据结构】班次规则验证结果
        /// </summary>
        private class ShiftRuleValidationResult
        {
            public string RuleType { get; set; } = string.Empty;
            public long PersonnelId { get; set; }
            public long TaskId { get; set; }
            public bool IsValid { get; set; }
            public List<string> Conflicts { get; set; } = new();
            public DateTime ValidatedAt { get; set; }
        }
    }
}