using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using NPP.SmartSchedue.Api.Contracts.Core.Enums;
using NPP.SmartSchedue.Api.Contracts.Services.Notification;
using NPP.SmartSchedue.Api.Contracts.Services.Notification.Input;
using NPP.SmartSchedue.Api.Contracts.Services.Notification.Output;
using NPP.SmartSchedue.Api.Contracts.Services.Work;
using NPP.SmartSchedue.Api.Services.Personnel;
using ZhonTai.Admin.Core.GrpcServices;
using ZhonTai.Admin.Services;
using ZhonTai.DynamicApi;
using ZhonTai.DynamicApi.Attributes;

namespace NPP.SmartSchedue.Api.Services.Notification;

/// <summary>
/// 通知服务 定时消息
/// </summary>
[DynamicApi(Area = "app")]
public class NotificationScheduledService : BaseService, IDynamicApi
{
    private readonly ILogger<NotificationScheduledService> _logger;
    private readonly IWorkOrderService _workOrderService;
    private readonly INotificationService _notificationService;
    private readonly IUserGrpcService _userService;
    private readonly PersonnelQualificationService _personnelQualificationService;

    public NotificationScheduledService(IWorkOrderService workOrderService,
        INotificationService notificationService,
        IUserGrpcService userService,
        ILogger<NotificationScheduledService> logger,
        PersonnelQualificationService personnelQualificationService)
    {
        _logger = logger;
        _workOrderService = workOrderService;
        _userService = userService;
        _notificationService = notificationService;
        _personnelQualificationService = personnelQualificationService;
    }


    /// <summary>
    /// 待提交任务提醒
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [AllowAnonymous]
    public async Task<IActionResult> CheckWorkOrderByPendingSubmit()
    {
        var setting = await GetNotificationSettingCache("任务待提交提醒");
        if (setting == null || !setting.IsEnabled)
        {
            _logger.LogWarning("任务待提交提醒未查询到有效的通知配置或已禁用");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        if (!IsWithinTimeWindow(setting, DateTime.Now))
        {
            _logger.LogInformation("当前不在通知时间窗内，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        var recipientIds = await GetNotificationPersonListAsync(setting);
        if (recipientIds == null || recipientIds.Count == 0)
        {
            _logger.LogInformation("人员组无成员，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        var pendingByCreator = await _workOrderService.GetPendingSubmitCountByCreatorAsync();
        if (pendingByCreator == null || pendingByCreator.Count == 0)
        {
            _logger.LogInformation("无待提交任务，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0 });
        }

        var intersectRecipients = pendingByCreator.Distinct().ToList();
        if (intersectRecipients.Count == 0)
        {
            _logger.LogInformation("人员组成员中无待提交任务创建人，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0 });
        }

        var now = DateTime.Now;
        var sendInputs = new List<SendNotificationInput>();

        foreach (var personId in intersectRecipients)
        {
            var lastSentAt = await GetLastSentAt(setting.Id, personId.Key, "WorkOrderPendingSubmit");
            if (!ShouldResendForPerson(setting, now, lastSentAt))
            {
                continue;
            }

            var count = pendingByCreator.TryGetValue(personId.Key, out var c) ? c : 0;
            if (count <= 0) continue;

            var variables = new Dictionary<string, string>
            {
                ["UserId"] = personId.ToString(),
                ["PendingCount"] = count.ToString(),
                ["Now"] = now.ToString("yyyy-MM-dd HH:mm"),
                ["count"] = count.ToString(),
            };

            var sysTitle = string.IsNullOrWhiteSpace(setting.SystemMessageTitleTemplate)
                ? "任务待提交提醒"
                : await Render(setting.SystemMessageTitleTemplate, variables);

            var sysContent = string.IsNullOrWhiteSpace(setting.SystemMessageContentTemplate)
                ? $"您有{count}个任务处于待提交状态，请及时处理"
                : await Render(setting.SystemMessageContentTemplate, variables);

            if (setting.IsSystemMessageEnabled)
            {
                sendInputs.Add(new SendNotificationInput
                {
                    SettingId = setting.Id,
                    NotificationType = NotificationTypeEnum.SystemMessage,
                    Title = sysTitle,
                    Content = sysContent,
                    RecipientPersonnelIds = new List<long> { personId.Key },
                    BusinessType = "WorkOrderPendingSubmit",
                    BusinessId = null,
                    BusinessData = "",
                    SendImmediately = true
                });
            }

            if (setting.IsEmailEnabled)
            {
                var emailSubject = string.IsNullOrWhiteSpace(setting.EmailSubjectTemplate)
                    ? sysTitle
                    : await Render(setting.EmailSubjectTemplate, variables);
                var emailContent = string.IsNullOrWhiteSpace(setting.EmailContentTemplate)
                    ? sysContent
                    : await Render(setting.EmailContentTemplate, variables);

                sendInputs.Add(new SendNotificationInput
                {
                    SettingId = setting.Id,
                    NotificationType = NotificationTypeEnum.Email,
                    Title = emailSubject,
                    Content = emailContent,
                    RecipientPersonnelIds = new List<long> { personId.Key },
                    BusinessType = "WorkOrderPendingSubmit",
                    BusinessId = null,
                    BusinessData = "",
                    SendImmediately = true
                });
            }
        }

        int sent = 0;
        foreach (var input in sendInputs)
        {
            var result = await _notificationService.SendNotificationAsync(input);
            sent += result.SuccessCount;
        }

        return new OkObjectResult(new { success = true, sent, targeted = intersectRecipients.Count });
    }

    /// <summary>
    /// 下周计划与请假提醒
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [AllowAnonymous]
    public async Task<IActionResult> CheckNextWeekPlanAndLeaveReminder()
    {
        var setting = await GetNotificationSettingCache("下周计划与请假提醒");
        if (setting == null || !setting.IsEnabled)
        {
            _logger.LogWarning("下周计划与请假提醒未查询到有效的通知配置或已禁用");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        var now = DateTime.Now;
        if (!IsWithinTimeWindow(setting, now))
        {
            _logger.LogInformation("当前不在通知时间窗内，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        var recipients = await GetNotificationPersonListAsync(setting);
        if (recipients == null || recipients.Count == 0)
        {
            _logger.LogInformation("人员组无成员，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        var nextWeekStart = now.Date.AddDays(7 - (int)now.DayOfWeek + 1);
        var nextWeekEnd = nextWeekStart.AddDays(6);
        var variables = new Dictionary<string, string>
        {
            ["StartDate"] = nextWeekStart.ToString("yyyy-MM-dd"),
            ["EndDate"] = nextWeekEnd.ToString("yyyy-MM-dd"),
            ["Now"] = now.ToString("yyyy-MM-dd HH:mm")
        };

        var sysTitle = string.IsNullOrWhiteSpace(setting.SystemMessageTitleTemplate)
            ? "下周计划与请假提醒"
            : await Render(setting.SystemMessageTitleTemplate, variables);

        var sysContent = string.IsNullOrWhiteSpace(setting.SystemMessageContentTemplate)
            ? $"请提交下周({variables["StartDate"]} ~ {variables["EndDate"]})的工作计划与请假安排"
            : await Render(setting.SystemMessageContentTemplate, variables);

        var emailSubject = string.IsNullOrWhiteSpace(setting.EmailSubjectTemplate)
            ? sysTitle
            : await Render(setting.EmailSubjectTemplate, variables);

        var emailContent = string.IsNullOrWhiteSpace(setting.EmailContentTemplate)
            ? sysContent
            : await Render(setting.EmailContentTemplate, variables);

        // 收集需发送目标并按类型合并为批量收件人，减少发送次数
        var systemTargets = new List<long>();
        var emailTargets = new List<long>();

        foreach (var pid in recipients)
        {
            var lastSentAt = await GetLastSentAt(setting.Id, pid, "NextWeekPlanAndLeave");
            if (!ShouldResendForPerson(setting, now, lastSentAt))
            {
                continue;
            }

            if (setting.IsSystemMessageEnabled)
            {
                systemTargets.Add(pid);
            }

            if (setting.IsEmailEnabled)
            {
                emailTargets.Add(pid);
            }
        }

        var sendInputs = new List<SendNotificationInput>();
        if (setting.IsSystemMessageEnabled && systemTargets.Count > 0)
        {
            sendInputs.Add(new SendNotificationInput
            {
                SettingId = setting.Id,
                NotificationType = NotificationTypeEnum.SystemMessage,
                Title = sysTitle,
                Content = sysContent,
                RecipientPersonnelIds = systemTargets.Distinct().ToList(),
                BusinessType = "NextWeekPlanAndLeave",
                BusinessId = null,
                BusinessData = "",
                SendImmediately = true
            });
        }

        if (setting.IsEmailEnabled && emailTargets.Count > 0)
        {
            sendInputs.Add(new SendNotificationInput
            {
                SettingId = setting.Id,
                NotificationType = NotificationTypeEnum.Email,
                Title = emailSubject,
                Content = emailContent,
                RecipientPersonnelIds = emailTargets.Distinct().ToList(),
                BusinessType = "NextWeekPlanAndLeave",
                BusinessId = null,
                BusinessData = "",
                SendImmediately = true
            });
        }

        int sent = 0;
        foreach (var input in sendInputs)
        {
            var result = await _notificationService.SendGroupNotificationAsync(input);
            sent += result.SuccessCount;
        }

        // targeted 返回真实被筛选后的人数
        var targeted = systemTargets.Union(emailTargets).Distinct().Count();
        return new OkObjectResult(new { success = true, sent, targeted });
    }


    /// <summary>
    /// 任务分配提醒（周五提醒排班管理员进行排班）
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [AllowAnonymous]
    public async Task<IActionResult> CheckFridayScheduleAssignmentReminder()
    {
        // 1. 读取通知配置
        var setting = await GetNotificationSettingCache("任务分配提醒-周五排班");
        if (setting == null || !setting.IsEnabled)
        {
            _logger.LogWarning("任务分配提醒-周五排班 未查询到有效的通知配置或已禁用");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        // 2. 基于时间窗与星期校验（建议由调度保证周五触发，此处再保护一次）
        var now = DateTime.Now;
        if (now.DayOfWeek != DayOfWeek.Friday)
        {
            _logger.LogInformation("今天不是周五，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }
        if (!IsWithinTimeWindow(setting, now))
        {
            _logger.LogInformation("当前不在通知时间窗内，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        // 3. 获取人员组成员（排班管理员）
        var recipients = await GetNotificationPersonListAsync(setting);
        if (recipients == null || recipients.Count == 0)
        {
            _logger.LogInformation("人员组无成员，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        // 4. 变量渲染
        var fridayDate = now.Date.ToString("yyyy-MM-dd");
        var weekOfYear = System.Globalization.ISOWeek.GetWeekOfYear(now);
        var variables = new Dictionary<string, string>
        {
            ["Now"] = now.ToString("yyyy-MM-dd HH:mm"),
            ["FridayDate"] = fridayDate,
            ["WeekOfYear"] = weekOfYear.ToString()
        };

        var sysTitle = string.IsNullOrWhiteSpace(setting.SystemMessageTitleTemplate)
            ? "任务分配提醒"
            : await Render(setting.SystemMessageTitleTemplate, variables);

        var sysContent = string.IsNullOrWhiteSpace(setting.SystemMessageContentTemplate)
            ? $"今天是周五（{fridayDate}），请及时完成下周的排班任务分配。"
            : await Render(setting.SystemMessageContentTemplate, variables);

        var emailSubject = string.IsNullOrWhiteSpace(setting.EmailSubjectTemplate)
            ? sysTitle
            : await Render(setting.EmailSubjectTemplate, variables);

        var emailContent = string.IsNullOrWhiteSpace(setting.EmailContentTemplate)
            ? sysContent
            : await Render(setting.EmailContentTemplate, variables);

        // 5. 频率控制 + 组发
        var systemTargets = new List<long>();
        var emailTargets = new List<long>();

        foreach (var pid in recipients)
        {
            var lastSentAt = await GetLastSentAt(setting.Id, pid, "FridayScheduleAssignmentReminder");
            if (!ShouldResendForPerson(setting, now, lastSentAt))
            {
                continue;
            }

            if (setting.IsSystemMessageEnabled) systemTargets.Add(pid);
            if (setting.IsEmailEnabled) emailTargets.Add(pid);
        }

        var sendInputs = new List<SendNotificationInput>();
        if (setting.IsSystemMessageEnabled && systemTargets.Count > 0)
        {
            sendInputs.Add(new SendNotificationInput
            {
                SettingId = setting.Id,
                NotificationType = NotificationTypeEnum.SystemMessage,
                Title = sysTitle,
                Content = sysContent,
                RecipientPersonnelIds = systemTargets.Distinct().ToList(),
                BusinessType = "FridayScheduleAssignmentReminder",
                BusinessId = null,
                BusinessData = "",
                SendImmediately = true
            });
        }

        if (setting.IsEmailEnabled && emailTargets.Count > 0)
        {
            sendInputs.Add(new SendNotificationInput
            {
                SettingId = setting.Id,
                NotificationType = NotificationTypeEnum.Email,
                Title = emailSubject,
                Content = emailContent,
                RecipientPersonnelIds = emailTargets.Distinct().ToList(),
                BusinessType = "FridayScheduleAssignmentReminder",
                BusinessId = null,
                BusinessData = "",
                SendImmediately = true
            });
        }

        // 6. 发送
        int sent = 0;
        foreach (var input in sendInputs)
        {
            // 与“下周计划与请假提醒”保持一致，组发
            var result = await _notificationService.SendGroupNotificationAsync(input);
            sent += result.SuccessCount;
        }

        var targeted = systemTargets.Union(emailTargets).Distinct().Count();
        return new OkObjectResult(new { success = true, sent, targeted });
    }

    /// <summary>
    /// 人员资质到期预警
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [AllowAnonymous]
    public async Task<IActionResult> CheckPersonnelQualificationExpiryReminder()
    {
        var setting = await GetNotificationSettingCache("人员资质到期预警");
        if (setting == null || !setting.IsEnabled)
        {
            _logger.LogWarning("人员资质到期预警未查询到有效的通知配置或已禁用");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        var now = DateTime.Now;
        if (!IsWithinTimeWindow(setting, now))
        {
            _logger.LogInformation("当前不在通知时间窗内，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        // // 人员范围：通知配置的人员组
        // var recipients = await GetNotificationPersonListAsync(setting);
        // if (recipients == null || recipients.Count == 0)
        // {
        //     _logger.LogInformation("人员组无成员，跳过发送");
        //     return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        // }

        // 查询这些人员的预警期内即将到期的资质
        var expiring = await _personnelQualificationService.GetExpiringAsync(DateTime.Today, null, includeExpired: false);
        if (expiring == null || expiring.Count == 0)
        {
            _logger.LogInformation("无资质到期预警数据，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0, targeted = 0 });
        }

        // 按人员聚合
        var grouped = expiring.GroupBy(x => x.PersonnelId)
                              .ToDictionary(g => g.Key, g => g.ToList());

        var sendInputs = new List<SendNotificationInput>();
        int targeted = 0;

        foreach (var pid in grouped.Distinct())
        {
            if (!grouped.TryGetValue(pid.Key, out var items) || items.Count == 0)
                continue;

            var lastSentAt = await GetLastSentAt(setting.Id, pid.Key, "PersonnelQualificationExpiry");
            if (!ShouldResendForPerson(setting, now, lastSentAt))
                continue;

            targeted++;

            // 组装模板变量
            var personName = items.FirstOrDefault()?.PersonnelName ?? "";
            var count = items.Count;
            var itemLines = items
                .OrderBy(i => i.DaysLeft)
                .Select(i =>
                {
                    var d = i.ExpiryDate?.ToString("yyyy-MM-dd") ?? "-";
                    return $"{i.QualificationName} 将于 {d} 到期，剩余 {i.DaysLeft} 天";
                });
                
            var itemsText = string.Join("; ", itemLines);

            var variables = new Dictionary<string, string>
            {
                ["UserId"] = pid.ToString(),
                ["PersonnelName"] = personName,
                ["Count"] = count.ToString(),
                ["Items"] = itemsText,
                ["Now"] = now.ToString("yyyy-MM-dd HH:mm")
            };

            var sysTitle = string.IsNullOrWhiteSpace(setting.SystemMessageTitleTemplate)
                ? "人员资质到期预警"
                : await Render(setting.SystemMessageTitleTemplate, variables);

            var sysContent = string.IsNullOrWhiteSpace(setting.SystemMessageContentTemplate)
                ? $"您有{count}条资质即将到期：{itemsText}"
                : await Render(setting.SystemMessageContentTemplate, variables);

            if (setting.IsSystemMessageEnabled)
            {
                sendInputs.Add(new SendNotificationInput
                {
                    SettingId = setting.Id,
                    NotificationType = NotificationTypeEnum.SystemMessage,
                    Title = sysTitle,
                    Content = sysContent,
                    RecipientPersonnelIds = new List<long> { pid.Key },
                    BusinessType = "PersonnelQualificationExpiry",
                    BusinessId = null,
                    BusinessData = "",
                    SendImmediately = true
                });
            }

            if (setting.IsEmailEnabled)
            {
                var emailSubject = string.IsNullOrWhiteSpace(setting.EmailSubjectTemplate)
                    ? sysTitle
                    : await Render(setting.EmailSubjectTemplate, variables);
                var emailContent = string.IsNullOrWhiteSpace(setting.EmailContentTemplate)
                    ? sysContent
                    : await Render(setting.EmailContentTemplate, variables);

                sendInputs.Add(new SendNotificationInput
                {
                    SettingId = setting.Id,
                    NotificationType = NotificationTypeEnum.Email,
                    Title = emailSubject,
                    Content = emailContent,
                    RecipientPersonnelIds = new List<long> { pid.Key },
                    BusinessType = "PersonnelQualificationExpiry",
                    BusinessId = null,
                    BusinessData = "",
                    SendImmediately = true
                });
            }
        }

        int sent = 0;
        foreach (var input in sendInputs)
        {
            var result = await _notificationService.SendNotificationAsync(input);
            sent += result.SuccessCount;
        }

        return new OkObjectResult(new { success = true, sent, targeted });
    }



    /// <summary>
    /// 统一对外：工作任务操作通知（供 WorkOrderIntegrationOperationService 调用）
    /// </summary>
    /// <param name="operationType">Modify/Delete/Cancel</param>
    /// <param name="taskId">任务ID</param>
    /// <param name="operatorUserId">操作者用户ID（可空）</param>
    /// <param name="operatorName">操作者名称（可空）</param>
    /// <param name="remarks">备注（可空）</param>
    /// <returns></returns>
    [HttpPost]
    [AllowAnonymous]
    public async Task<IActionResult> SendWorkOrderOperationNotificationAsync(
        string operationType,
        long taskId,
        long? operatorUserId = null,
        string operatorName = null,
        string remarks = null,
        IList<long> designatedPersonnelIds = null,
        IList<string> designatedPersonnelNames = null)
    {
        // 1. 读取统一通知配置
        var setting = await GetNotificationSettingCache("工作任务操作通知");
        if (setting == null || !setting.IsEnabled)
        {
            _logger.LogWarning("工作任务操作通知 未查询到有效的通知配置或已禁用");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        var now = DateTime.Now;
        if (!IsWithinTimeWindow(setting, now))
        {
            _logger.LogInformation("当前不在通知时间窗内，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        // 2. 收件人
        var recipients = await GetNotificationPersonListAsync(setting);
        recipients.AddRange(designatedPersonnelIds);
        recipients = recipients.Distinct().ToList();

        if (recipients == null || recipients.Count == 0)
        {
            _logger.LogInformation("人员组无成员，跳过发送");
            return new OkObjectResult(new { success = true, sent = 0, skipped = 0 });
        }

        // 3. 业务类型区分，便于历史频率控制
        string businessType = operationType?.ToLower() switch
        {
            "modify" => "WorkOrderModified",
            "delete" => "WorkOrderDeleted",
            "cancel" => "WorkOrderCancelled",
            _ => "WorkOrderOperation"
        };

        // 4. 模板变量
        var variables = new Dictionary<string, string>
        {
            ["OperationType"] = operationType ?? string.Empty,
            ["TaskId"] = taskId.ToString(),
            ["OperatorUserId"] = operatorUserId?.ToString() ?? string.Empty,
            ["OperatorName"] = operatorName ?? string.Empty,
            ["Remarks"] = remarks ?? string.Empty,
            ["Now"] = now.ToString("yyyy-MM-dd HH:mm"),
            ["DesignatedPersonnelIds"] = designatedPersonnelIds != null ? string.Join(",", designatedPersonnelIds) : string.Empty,
            ["DesignatedPersonnelNames"] = designatedPersonnelNames != null ? string.Join(",", designatedPersonnelNames) : string.Empty
        };

        var sysTitle = string.IsNullOrWhiteSpace(setting.SystemMessageTitleTemplate)
            ? $"任务{operationType}通知"
            : await Render(setting.SystemMessageTitleTemplate, variables);

        var sysContent = string.IsNullOrWhiteSpace(setting.SystemMessageContentTemplate)
            ? $"任务({taskId})已执行{operationType}操作。{(string.IsNullOrEmpty(remarks) ? "" : "备注：" + remarks)}"
            : await Render(setting.SystemMessageContentTemplate, variables);

        var emailSubject = string.IsNullOrWhiteSpace(setting.EmailSubjectTemplate)
            ? sysTitle
            : await Render(setting.EmailSubjectTemplate, variables);

        var emailContent = string.IsNullOrWhiteSpace(setting.EmailContentTemplate)
            ? sysContent
            : await Render(setting.EmailContentTemplate, variables);

        // 5. 频率控制 + 组发
        var systemTargets = new List<long>();
        var emailTargets = new List<long>();

        foreach (var pid in recipients)
        {
            var lastSentAt = await GetLastSentAt(setting.Id, pid, businessType);
            if (!ShouldResendForPerson(setting, now, lastSentAt))
            {
                continue;
            }

            if (setting.IsSystemMessageEnabled) systemTargets.Add(pid);
            if (setting.IsEmailEnabled) emailTargets.Add(pid);
        }

        var sendInputs = new List<SendNotificationInput>();
        if (setting.IsSystemMessageEnabled && systemTargets.Count > 0)
        {
            sendInputs.Add(new SendNotificationInput
            {
                SettingId = setting.Id,
                NotificationType = NotificationTypeEnum.SystemMessage,
                Title = sysTitle,
                Content = sysContent,
                RecipientPersonnelIds = systemTargets.Distinct().ToList(),
                BusinessType = businessType,
                BusinessId = taskId,
                BusinessData = System.Text.Json.JsonSerializer.Serialize(new {
                    OperationType = operationType, TaskId = taskId, OperatorUserId = operatorUserId, OperatorName = operatorName, Remarks = remarks
                }),
                SendImmediately = true
            });
        }

        if (setting.IsEmailEnabled && emailTargets.Count > 0)
        {
            sendInputs.Add(new SendNotificationInput
            {
                SettingId = setting.Id,
                NotificationType = NotificationTypeEnum.Email,
                Title = emailSubject,
                Content = emailContent,
                RecipientPersonnelIds = emailTargets.Distinct().ToList(),
                BusinessType = businessType,
                BusinessId = taskId,
                BusinessData = System.Text.Json.JsonSerializer.Serialize(new {
                    OperationType = operationType, TaskId = taskId, OperatorUserId = operatorUserId, OperatorName = operatorName, Remarks = remarks
                }),
                SendImmediately = true
            });
        }

        int sent = 0;
        foreach (var input in sendInputs)
        {
            var result = await _notificationService.SendGroupNotificationAsync(input);
            sent += result.SuccessCount;
        }

        var targeted = systemTargets.Union(emailTargets).Distinct().Count();
        return new OkObjectResult(new { success = true, sent, targeted, businessType });
    }

    private async Task<string> Render(string template, Dictionary<string, string> variables)
    {
        var isValid = await _notificationService.ValidateTemplateAsync(template);
        if (!isValid) return template;
        if (variables == null || variables.Count == 0) return template;
        var result = template;
        foreach (var kv in variables)
        {
            var placeholder = $"{{{kv.Key}}}";
            result = result.Replace(placeholder, kv.Value ?? string.Empty, StringComparison.Ordinal);
        }
        return result;
    }

    private async Task<DateTime?> GetLastSentAt(long settingId, long personnelId, string businessType)
    {
        try
        {
            var histories = await _notificationService.GetNotificationHistoryPageAsync(new ZhonTai.Admin.Core.Dto.PageInput<NotificationHistoryPageInput>
            {
                CurrentPage = 0,
                PageSize = 10000,
                Filter = new NotificationHistoryPageInput
                {
                    NotificationSettingId = settingId,
                    RecipientPersonnelId = personnelId,
                    BusinessType = businessType
                }
            });

            var item = histories.List.FirstOrDefault();
            return item?.ActualSendTime ?? item?.PlannedSendTime;
        }
        catch
        {
            return null;
        }
    }

    private async Task<NotificationSettingOutput> GetNotificationSettingCache(string key)
    {
        var settings = await _notificationService.GetNotificationSettingListAsync(true);
        return settings.FirstOrDefault(m => m.NotificationName == key);
    }

    private async Task<List<long>> GetNotificationPersonListAsync(NotificationSettingOutput? setting = null,
        List<long>? otherPersons = null)
    {
        var notificationPersonList = new List<long>();

        if (setting != null)
        {
            notificationPersonList.AddRange(await _notificationService.GetPersonnelGroupMembersAsync(setting.PersonnelGroupId));
        }

        if (otherPersons != null && otherPersons.Count > 0)
        {
            notificationPersonList.AddRange(otherPersons);
        }

        return notificationPersonList.Distinct().ToList();
    }

    private bool ShouldResendForPerson(NotificationSettingOutput setting, DateTime now, DateTime? lastSentAt)
    {
        if (!IsWithinTimeWindow(setting, now)) return false;
        if (setting.FrequencyType == NotificationFrequencyEnum.Once)
        {
            return lastSentAt == null;
        }

        if (setting.FrequencyType == NotificationFrequencyEnum.FixedInterval)
        {
            if (lastSentAt == null) return true;
            var interval = setting.IntervalMinutes.GetValueOrDefault(0);
            if (interval <= 0) return false;
            return now - lastSentAt.Value >= TimeSpan.FromMinutes(interval);
        }

        return false;
    }

    private bool IsWithinTimeWindow(NotificationSettingOutput setting, DateTime now)
    {
        if (string.IsNullOrWhiteSpace(setting.StartTime) || string.IsNullOrWhiteSpace(setting.EndTime)) return true;
        if (!TimeOnly.TryParse(setting.StartTime, out var start)) return true;
        if (!TimeOnly.TryParse(setting.EndTime, out var end)) return true;
        var t = TimeOnly.FromDateTime(now);
        return t >= start && t < end;
    }
}