package com.seer.teach.mp.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.exception.CommonException;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.mp.entity.MpMessageGroupUserEntity;
import com.seer.teach.mp.entity.MpTemplateMessageEntity;
import com.seer.teach.mp.entity.MpTemplateMessageMappingEntity;
import com.seer.teach.mp.factory.MpServiceFactory;
import com.seer.teach.mp.mapper.MpTemplateMessageMapper;
import com.seer.teach.mp.service.IMpTemplateMessageMappingService;
import com.seer.teach.mp.service.IMpTemplateMessageService;
import com.seer.teach.mp.service.IMqMessageGroupUserService;
import com.seer.teach.mp.service.dto.MpTemplateMessageDTO;
import com.seer.teach.user.api.UserInfoServiceApi;
import com.seer.teach.user.api.dto.UserAuthDTO;
import com.seer.teach.user.api.dto.UserAuthQueryDTO;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpTemplateMsgService;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import jakarta.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 模板消息表 服务实现类
 * </p>
 *
 * @author Wang
 * @since 2025-08-09 15:07:09
 */
@Slf4j
@Service
public class MpTemplateMessageServiceImpl extends ServiceImpl<MpTemplateMessageMapper, MpTemplateMessageEntity> implements IMpTemplateMessageService {

    @Resource
    private MpServiceFactory mpServiceFactory;

    @Resource
    private UserInfoServiceApi userInfoServiceApi;

    @Resource
    private IMpTemplateMessageMappingService mpTemplateMessageMappingService;

    @Resource
    private IMqMessageGroupUserService mqMessageGroupUserService;


    @Override
    public List<MpTemplateMessageEntity> getTemplateMessageHistory(String businessId) {
        return super.list(new LambdaQueryWrapper<>(MpTemplateMessageEntity.class).eq(MpTemplateMessageEntity::getBusinessId, businessId));
    }

    /**
     * 发送模板消息
     */
    public void sendTemplateMessage(MpTemplateMessageDTO mpTemplateMessageDTO) {
        if(CollectionUtil.isEmpty(mpTemplateMessageDTO.getUserIds()) && CollectionUtil.isEmpty(mpTemplateMessageDTO.getGroupIds())){
            throw new CommonException(ResultCodeEnum.MESSAGE_GROUP_USER_NON_EMPTY);
        }
        Collection<Integer> userIds = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(mpTemplateMessageDTO.getGroupIds()) && mpTemplateMessageDTO.getNotifyType().equalsIgnoreCase("group")){
            Collection<MpMessageGroupUserEntity> groupUsers = mqMessageGroupUserService.getGroupUserByGroupIds(mpTemplateMessageDTO.getGroupIds());

            AssertUtils.notEmpty(groupUsers, ResultCodeEnum.MESSAGE_GROUP_IS_EMPTY);

            userIds.addAll(groupUsers.stream().map(MpMessageGroupUserEntity::getUserId).collect(Collectors.toList()));
        }else{
            userIds.addAll(mpTemplateMessageDTO.getUserIds());
        }

        // 1. 获取用户的openId
        UserAuthQueryDTO userAuthQueryDTO = new UserAuthQueryDTO();
        userAuthQueryDTO.setUserIds(userIds);
        userAuthQueryDTO.setAppId(mpTemplateMessageDTO.getAppId());
        List<UserAuthDTO> users = userInfoServiceApi.getUserAuthListByUserIdsAndAppId(userAuthQueryDTO);
        if( CollectionUtil.isEmpty( users)){
            log.warn("用户列表为空，请联系管理员");
            return;
        }
        log.info("userInfoServiceApi 获取的用户列表: {}",users);
        Map<String, Object> data = mpTemplateMessageDTO.getData();

        List<MpTemplateMessageEntity> mpTemplateMessages = new ArrayList<>(users.size());
        for(UserAuthDTO user : users){
            log.info("用户[{}]开始发送模板消息: {} ",user.getUserId(),user.getOpenId());

            // 2. 构建消息
            WxMpTemplateMessage message = buildWechatMessage(mpTemplateMessageDTO, data, user.getOpenId());

            // 3. 调用微信API发送
            WxMpTemplateMsgService wxMpTemplateMsgService = mpServiceFactory.getWxMpTemplateMsgService(mpTemplateMessageDTO.getAppId());

            MpTemplateMessageEntity mpTemplateMessageEntity = new MpTemplateMessageEntity();
            mpTemplateMessageEntity.setAppId(mpTemplateMessageDTO.getAppId());
            mpTemplateMessageEntity.setUserId(user.getUserId());
            mpTemplateMessageEntity.setBusinessId(mpTemplateMessageDTO.getBusinessId());
            mpTemplateMessageEntity.setOpenid(user.getOpenId());
            mpTemplateMessageEntity.setTemplateId(mpTemplateMessageDTO.getTemplateId());
            mpTemplateMessageEntity.setData(JSONUtil.toJsonStr(data));
            try {
                if(StrUtil.isNotEmpty(user.getOpenId())){
                    String msgId = wxMpTemplateMsgService.sendTemplateMsg(message);
                    mpTemplateMessageEntity.setMsgId(msgId);
                    log.info("发送模板消息成功: {} ", msgId);
                    mpTemplateMessageEntity.setStatus(MpTemplateMessageEntity.TEMPLATE_MESSAGE_STATUS_SUCCESS);
                }else{
                    mpTemplateMessageEntity.setStatus(MpTemplateMessageEntity.TEMPLATE_MESSAGE_STATUS_FAILED);
                    mpTemplateMessageEntity.setErrorMsg("用户没有绑定微信服务号");
                    log.info("用户没有绑定微信服务号: {}", user.getUserId());
                }
            } catch (WxErrorException e) {
                log.error("发送模板消息失败:{} ",e.getMessage(),e);
                mpTemplateMessageEntity.setErrorMsg(e.getMessage());
                mpTemplateMessageEntity.setStatus(MpTemplateMessageEntity.TEMPLATE_MESSAGE_STATUS_FAILED);
            }
            mpTemplateMessages.add(mpTemplateMessageEntity);
        }
        boolean saved = super.saveBatch(mpTemplateMessages);
        log.info("保存模板消息结果: " + saved);
    }

    /**
     * 转换数据格式
     */
    private List<WxMpTemplateData> convertToWxMpData(Map<String, String> data) {
        return data.entrySet().stream()
                .map(entry -> new WxMpTemplateData(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }


    /**
     * 构建微信模板消息
     * @param mpTemplateMessageDTO 模板配置
     * @param fieldValues 系统字段键值对
     * @param openid 接收者openid
     * @return 微信模板消息
     */
    public WxMpTemplateMessage buildWechatMessage(MpTemplateMessageDTO mpTemplateMessageDTO, Map<String, Object> fieldValues, String openid) {
        // 1. 获取模板映射配置
        String templateId = mpTemplateMessageDTO.getTemplateId();
        List<MpTemplateMessageMappingEntity> mappings = mpTemplateMessageMappingService.findByTemplateId(templateId);
        if (mappings.isEmpty()) {
            throw new RuntimeException("未找到模板配置: " + templateId);
        }

        // 2. 构建数据映射
        Map<String, String> data = new HashMap<>();

        for (MpTemplateMessageMappingEntity mapping : mappings) {
            String systemField = mapping.getSystemField();
            Object value = fieldValues.get(systemField);

            // 处理空值
            if (value == null) {
                if (mapping.getIsRequired()) {
                    throw new RuntimeException("必填字段缺失: " + systemField);
                }
                value = mapping.getDefaultValue();
                if (value == null) continue;
            }

            // 添加到data
            data.put(mapping.getWechatField(), StrUtil.toString( value));
        }

        // 3. 构建最终消息
        WxMpTemplateMessage message = new WxMpTemplateMessage();
        message.setToUser(openid);
        message.setTemplateId(templateId);
        message.setUrl(mpTemplateMessageDTO.getUrl());
        message.setData(convertToWxMpData(data));
        if(StringUtils.hasText(mpTemplateMessageDTO.getMiniProgramAppId()) && StringUtils.hasText(mpTemplateMessageDTO.getMiniProgramPagePath())){
            message.setMiniProgram(new WxMpTemplateMessage.MiniProgram(mpTemplateMessageDTO.getMiniProgramAppId(), mpTemplateMessageDTO.getMiniProgramPagePath(), true));
        }
        return message;
    }
}