package cn.newfeifan.mall.module.trade.utils.wechat;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import cn.newfeifan.mall.module.member.dal.dataobject.user.MemberUserDO;
import cn.newfeifan.mall.module.member.service.user.MemberUserService;
import cn.newfeifan.mall.module.system.controller.admin.auth.vo.AuthLoginRespVO;
import cn.newfeifan.mall.module.system.dal.dataobject.config.SystemConfigDO;
import cn.newfeifan.mall.module.system.dal.dataobject.user.AdminUserDO;
import cn.newfeifan.mall.module.system.dal.dataobject.wechatmsgtemplate.WechatMsgTemplateDO;
import cn.newfeifan.mall.module.system.enums.logger.LoginLogTypeEnum;
import cn.newfeifan.mall.module.system.service.auth.AdminAuthService;
import cn.newfeifan.mall.module.system.service.config.SystemConfigService;
import cn.newfeifan.mall.module.system.service.permission.PermissionService;
import cn.newfeifan.mall.module.system.service.social.SocialUserService;
import cn.newfeifan.mall.module.system.service.user.AdminUserService;
import cn.newfeifan.mall.module.system.service.wechatmsgtemplate.WechatMsgTemplateService;
import cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo.MessageLogSaveReqVO;
import cn.newfeifan.mall.module.trade.enums.wxmessage.WcChatMessageTemplateIdEnum;
import cn.newfeifan.mall.module.trade.service.messagelog.MessageLogService;
import com.google.gson.JsonObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;

import static cn.newfeifan.mall.module.system.constant.SystemConstants.WX_TICK_KEY_APPID;
import static cn.newfeifan.mall.module.trade.enums.MessageTemplateConstants.*;

/**
 * 发送微信消息的工具类
 */
@Data
@Component
@Slf4j
public class WcChatMessageUtils {

    @Value("${wx.mp.app-id}")
    private String appid;
    @Value("${wx.mp.secret}")
    private String Wxgsecret;

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private WechatMsgTemplateService wechatMsgTemplateService;
    @Resource
    private SocialUserService socialUserService;
    @Resource
    private MessageLogService messageLogService;
    @Resource
    private SystemConfigService configService;
    @Resource
    private PermissionService permissionService;
    @Resource
    private MemberUserService memberUserService;
    @Resource
    private AdminAuthService authService;
    @Resource
    private AdminUserService adminUserService;

    /**
     * 获取微信的accessToken
     *
     * @return accessToken
     */
    public String getAccessToken() {

        String accessToken = stringRedisTemplate.opsForValue().get(WX_TICK_KEY_APPID);

        if (StrUtil.isEmpty(accessToken)) {
            // 服务号的appid以及秘钥
            String requestUrl = StrUtil.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}", appid, Wxgsecret);
            String returnMsg = HttpUtil.get(requestUrl);
            cn.hutool.json.JSONObject responseJsonObject = JSONUtil.parseObj(returnMsg);
            if (ObjectUtil.isNull(responseJsonObject)) try {
                throw new Exception("响应异常:获取信息为空!");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            accessToken = responseJsonObject.getStr("access_token");

            //微信的accessToken的失效时间是两个小时,这里改为一小时五十五分钟,怕双方的时间误差导致accessToken失效
            long expireTime = 60 * 60 + 55 * 60; // 1小时55分钟转换为秒
            stringRedisTemplate.opsForValue().set(WX_TICK_KEY_APPID, accessToken, expireTime, java.util.concurrent.TimeUnit.SECONDS);
        }

        log.info("===========Access_token:{}", accessToken);

        return accessToken;
    }

    /**
     * 发送微信消息
     *
     * @param userId 接口消息的用户id
     * @param data   模板参数
     */
    private void sendWxgMessage(Long userId, JsonObject data, String wechatMsgTemplateId, Long systemUserId, Long objectId, String userOpenId) {
        String templateId = getTemplateId(wechatMsgTemplateId).getWechatMsgTemplateId(); // 模板id
        String url = getDoMain(wechatMsgTemplateId, objectId, systemUserId);       // 跳转路径(小程序之外)
        String client_msg_id = UUID.randomUUID().toString();  // 防重入id


        WeChatTemplateMessage message = new WeChatTemplateMessage();
        message.setTouser(userOpenId);
        message.setTemplate_id(templateId);
        message.setUrl(url);
        message.setClient_msg_id(client_msg_id);
        message.setData(data);

        sendWecChatMessage(userId, wechatMsgTemplateId, systemUserId, objectId, userOpenId, message,1);
    }

    private void sendWecChatMessage(Long userId, String wechatMsgTemplateId, Long systemUserId, Long objectId, String userOpenId, WeChatTemplateMessage message, int maxRetries) {
        // 发送消息
        String returnMsg = HttpUtil.post(StrUtil.format("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={}", getAccessToken()), message.toString());
        cn.hutool.json.JSONObject jsonObject2 = JSONUtil.parseObj(returnMsg);
        String errmsg = jsonObject2.getStr("errmsg");

        //记录发送的微信消息
        MessageLogSaveReqVO messageLogSaveReqVO = MessageLogSaveReqVO.builder()
                .openid(userOpenId)
                .memberUserId(userId)
                .systemUserId(systemUserId)
                .wechatMsgTemplateId(Long.valueOf(wechatMsgTemplateId))
                .wechatMsgTemplateParams(message.toString())
                .objectId(objectId)
                .sendStatus(true)
                .sendTime(LocalDateTime.now())
                .responseResult(returnMsg)
                .build();
        if (!StrUtil.equals("ok", errmsg)) {
            log.info("=====消息发送失败,原因:{}", errmsg);
            messageLogSaveReqVO.setSendStatus(false);
        }

        messageLogService.createMessageLog(messageLogSaveReqVO);

        // 如果微信的accessToken失效,则重新获取,最多重试3次
        if (jsonObject2.getStr("errcode").equals("40001") && maxRetries <= 3) {
            maxRetries++;
            stringRedisTemplate.delete(WX_TICK_KEY_APPID);
            sendWecChatMessage(userId, wechatMsgTemplateId, systemUserId, objectId, userOpenId, message, maxRetries);
        }
    }

    /**
     * 获取待发货模板参数
     *
     * @return 待发货模板参数
     */
    public JsonObject getTemplateData(List<String> dataParams, List<String> params) {

        JsonObject data = new JsonObject();

        // 添加字段及其值
        for (int i = 0; i < Math.min(params.size(), dataParams.size()); i++) {
            String paramName = dataParams.get(i);
            String paramValue = params.get(i);

            JsonObject obj = new JsonObject();
            obj.addProperty("value", paramValue);
            data.add(paramName, obj);
        }

        return data;
    }

    /**
     * 发送微信信息
     *
     * @param templateId   自定义消息模板id
     * @param params       消息参数
     * @param systemUserId 系统用户id
     * @param objectId     对象id
     */
    public void sendWcChatMessage(String templateId, List<String> params, Long systemUserId, Long objectId) {
        WechatMsgTemplateDO template = getTemplateId(templateId);
        String messageTemplateParameters = template.getMessageTemplateParameters();

        // 去除首尾的括号，并去除空格
        messageTemplateParameters = messageTemplateParameters.substring(1, messageTemplateParameters.length() - 1).trim();

        // 使用逗号分割字符串，并去除空格
        String[] parts = messageTemplateParameters.split(",\\s*");

        // 创建集合并将数组转换为集合
        List<String> dataParams = Arrays.asList(parts);
        JsonObject templateData = getTemplateData(dataParams, params);

        // 组装消息内容
        String userOpenId;
        // 判断系统用户是否有接收消息的权限
        if (!isHavePermission(systemUserId, templateId)) {
            return;
        }

        // 获取系统用户绑定的会员用户集
        Map<String, Long> openMap = new HashMap<>();
        List<MemberUserDO> memberUserDOS = getMemberUserBySystemUserId(systemUserId);
        for (MemberUserDO memberUserDO : memberUserDOS) {
            userOpenId = getOpenId(memberUserDO.getId());

            //如果用户没有绑定微信,则不发送消息
            if (userOpenId == null) {
                continue;
            }

            openMap.put(userOpenId, memberUserDO.getId());
        }

        openMap.forEach((k, v) -> sendWxgMessage(v, templateData, templateId, systemUserId, objectId, k));
    }

    /**
     * 判断系统用户是否有接收消息的权限
     *
     * @param userId     用户id
     * @param templateId 自定义的模板id
     * @return 是否有权限
     */
    public Boolean isHavePermission(Long userId, String templateId) {
        if (templateId.equals(WcChatMessageTemplateIdEnum.AFTER_SALE_NO_CHECK2.getTemplateId())) {
            // 售后待审核
            return permissionService.isHavePermission(userId, AFTER_SALE_NO_CHECK_List);
        } else if (templateId.equals(WcChatMessageTemplateIdEnum.ORDER_NO_DELIVERY2.getTemplateId())) {
            // 订单待发货
            return permissionService.isHavePermission(userId, ORDER_NO_DELIVERY_List);
        } else if (templateId.equals(WcChatMessageTemplateIdEnum.MERCHANT_APPLY_CHECK.getTemplateId())) {
            // 商户入驻审核
            return permissionService.isHavePermission(userId, MERCHANT_APPLY_CHECK_LIST);
        }
        return false;
    }

    /**
     * 获取不同端域名(不同的端的代码略有不同)
     *
     * @param templateId 自定义模板id
     * @return 域名加路径
     */
    public String getDoMain(String templateId, Long objectId, Long systemUserId) {
        SystemConfigDO redisConfig = configService.getRedisConfig();
        if (templateId.equals(WcChatMessageTemplateIdEnum.ORDER_DELIVERY2.getTemplateId())) {
            //订单已发货
            return redisConfig.getMallDomain() + "/#/pages/order/detail?id=" + objectId;
        } else if (templateId.equals(WcChatMessageTemplateIdEnum.AFTER_SALE_CHECK2.getTemplateId())) {
            //售后订单审核完成
            return redisConfig.getMallDomain() + "/#/pages/order/aftersale/detail?id=" + objectId;
        } else if (templateId.equals(WcChatMessageTemplateIdEnum.AFTER_SALE_NO_CHECK2.getTemplateId())) {
            //售后订单待审核
            AdminUserDO systemUser = adminUserService.getUser(systemUserId);
            AuthLoginRespVO token = authService.createTokenAfterLoginSuccess(systemUser.getId(), systemUser.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
//            return redisConfig.getMerchantDomain() + "/after-sale";
            return redisConfig.getMerchantDomain() + "/login" + "?accessToken=" + token.getAccessToken() + "&refreshToken=" + token.getRefreshToken();
        } else if (templateId.equals(WcChatMessageTemplateIdEnum.ORDER_NO_DELIVERY2.getTemplateId())) {
            //订单待发货
            AdminUserDO systemUser = adminUserService.getUser(systemUserId);
            AuthLoginRespVO token = authService.createTokenAfterLoginSuccess(systemUser.getId(), systemUser.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
//            return redisConfig.getMerchantDomain() + "/order";
            return redisConfig.getMerchantDomain() + "/login" + "?accessToken=" + token.getAccessToken() + "&refreshToken=" + token.getRefreshToken();
        } else if(templateId.equals(WcChatMessageTemplateIdEnum.MERCHANT_APPLY_CHECK.getTemplateId())){
            // 商户入驻申请审批通知
            AdminUserDO systemUser = adminUserService.getUser(systemUserId);
            AuthLoginRespVO token = authService.createTokenAfterLoginSuccess(systemUser.getId(), systemUser.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
            return redisConfig.getPlatformDomain() + "/login" + "?accessToken=" + token.getAccessToken() + "&refreshToken=" + token.getRefreshToken();
        } else if(templateId.equals(WcChatMessageTemplateIdEnum.MERCHANT_APPLY_CHECK_RESULT.getTemplateId())){
            // 商户入驻审核结果通知
            return redisConfig.getMallDomain() + "/#/pages/public/merchant";
        }
        return null;
    }

    /**
     * 通过自己定义消息模板id获取微信第三方模板
     *
     * @param wechatMsgTemplateId 自己定义消息模板id
     * @return 微信第三方模板
     */
    private WechatMsgTemplateDO getTemplateId(String wechatMsgTemplateId) {
        return wechatMsgTemplateService.getWechatSsgTemplate(Long.valueOf(wechatMsgTemplateId));
    }

    private String getOpenId(Long userId) {
        return socialUserService.getOpenIdByUserId(userId);
    }

    private List<MemberUserDO> getMemberUserBySystemUserId(Long systemUserId) {
        return memberUserService.getUserListBySystemUserId(systemUserId);
    }
}
