package com.njcn.rdms.module.project.service.duealert;

import com.njcn.rdms.module.project.constant.DueAlertConstants;
import com.njcn.rdms.module.project.dal.dataobject.duealert.DueAlertRecordDO;
import com.njcn.rdms.module.project.dal.mysql.duealert.DueAlertRecordMapper;
import com.njcn.rdms.module.project.framework.notify.NotifySendEvent;
import com.njcn.rdms.module.project.framework.notify.NotifyTemplateCodeConstants;
import com.njcn.rdms.module.system.enums.notify.NotifyMessageLevelConstants;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;

/**
 * 告警发送实现：去重记录与事件发布同事务（NotifySendEvent 事务红线），
 * 唯一索引冲突 = 已发过（并发/多实例/同日重复执行），静默跳过。
 */
@Service
@Slf4j
public class DueAlertSendServiceImpl implements DueAlertSendService {

    @Resource
    private DueAlertRecordMapper dueAlertRecordMapper;
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendAlert(DueAlertCandidate candidate, String alertType, LocalDate today) {
        DueAlertRecordDO record = new DueAlertRecordDO();
        record.setObjectType(candidate.getObjectType().getCode());
        record.setObjectId(candidate.getObjectId());
        record.setAlertType(alertType);
        record.setPlannedEndDate(candidate.getPlannedEndDate());
        record.setAlertDate(today);
        try {
            dueAlertRecordMapper.insert(record);
        } catch (DuplicateKeyException e) {
            log.info("[sendAlert][告警记录已存在，跳过 objectType({}) objectId({}) alertType({})]",
                    record.getObjectType(), record.getObjectId(), alertType);
            return;
        }

        boolean approaching = DueAlertConstants.ALERT_TYPE_APPROACHING.equals(alertType);
        // 按「身份 + 紧急度」定级：逾期高于临期，同紧急度内负责人高于协办人
        int ownerLevel = approaching ? NotifyMessageLevelConstants.REMIND : NotifyMessageLevelConstants.SEVERE;
        int assigneeLevel = approaching ? NotifyMessageLevelConstants.NORMAL : NotifyMessageLevelConstants.WARN;
        Map<String, Object> params = new HashMap<>();
        params.put("objectTypeName", candidate.getObjectType().getDisplayName());
        params.put("objectName", candidate.getObjectName());
        params.put("plannedEndDate", candidate.getPlannedEndDate().toString());
        // 对象标识附加参数：不在模板正文渲染，存进消息参数 JSON，供逾期"未读不重发"按对象匹配
        params.put(DueAlertConstants.PARAM_OBJECT_TYPE, candidate.getObjectType().getCode());
        params.put(DueAlertConstants.PARAM_OBJECT_ID, String.valueOf(candidate.getObjectId()));
        if (approaching) {
            params.put("remainingDays", ChronoUnit.DAYS.between(today, candidate.getPlannedEndDate()));
        }

        if (candidate.getOwnerUserIds() != null && !candidate.getOwnerUserIds().isEmpty()) {
            applicationEventPublisher.publishEvent(NotifySendEvent.of(candidate.getOwnerUserIds(),
                    approaching ? NotifyTemplateCodeConstants.DUE_ALERT_APPROACHING_OWNER
                            : NotifyTemplateCodeConstants.DUE_ALERT_OVERDUE_OWNER,
                    params, ownerLevel));
        }
        if (candidate.getAssigneeUserIds() != null && !candidate.getAssigneeUserIds().isEmpty()) {
            applicationEventPublisher.publishEvent(NotifySendEvent.of(candidate.getAssigneeUserIds(),
                    approaching ? NotifyTemplateCodeConstants.DUE_ALERT_APPROACHING_ASSIGNEE
                            : NotifyTemplateCodeConstants.DUE_ALERT_OVERDUE_ASSIGNEE,
                    params, assigneeLevel));
        }
    }

}
