package com.ghy.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ghy.common.enums.OrderStatus;
import com.ghy.common.enums.WxMsgEnum;
import com.ghy.common.utils.DateUtils;
import com.ghy.system.config.WxMsgConfig;
import com.ghy.system.service.IWxMsgService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 但星霖
 * @date 2023-01-06 14:02
 * 微信消息推送业务接口实现层
 */
@Slf4j
@Service
public class WxMsgServiceImpl implements IWxMsgService {

    @Autowired
    private RestTemplate restTemplate;

    @Value("${wx.appId}")
    private String appId;
    @Value("${wx.secret}")
    private String secret;

    @Value("${wx.mallAppId}")
    private String mallAppId;
    @Value("${wx.mallSecret}")
    private String mallSecret;

    @Override
    public Boolean sendMsg(String openId, String remind, String orderId, String name, OrderStatus orderStatus, Long time) {
        WxMsgConfig wxMsgConfig = getQRCodeMsgConfig(openId, remind, orderId, name, orderStatus, time);
        // 通知urL
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + getAccessToken(true);
        log.info("微信消息通知请求地址：{}", url);
        log.info("微信消息通知请求参数：{}", wxMsgConfig);
        JSONObject responseData = postData(url, wxMsgConfig);
        log.info("微信消息通知请求参数：{}", JSON.toJSONString(responseData));
        Integer errorCode = responseData.getInteger("errcode");
        String errorMessage = responseData.getString("errmsg");
        if (errorCode == 0) {
            log.info("用户：" + "openId" + "消息推送成功");
            return true;
        } else {
            log.error("微信消息通知请求参数,errcode：{},errorMessage：{}", errorCode, errorMessage);
        }
        return false;
    }

    @Override
    public void sendWxMsg(String openId, WxMsgEnum wxMsgEnum, Map<String, Object> params) {
        WxMsgConfig wxMsgConfig = buildMsgDto(openId, wxMsgEnum, params);
        Boolean flag = true;
        if(wxMsgEnum.getTempCode().equals(WxMsgEnum.CUSTOMER_ORDER.getTempCode())){
            flag = false;
        }
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + getAccessToken(flag);
        log.info("微信消息通知请求 url: {} , 参数: {}",url,  wxMsgConfig);
        JSONObject responseData = postData(url, wxMsgConfig);
        log.info("微信消息通知请求参数：{}", JSON.toJSONString(responseData));
        Integer errorCode = responseData.getInteger("errcode");
        String errorMessage = responseData.getString("errmsg");
        if (errorCode == 0) {
            log.info("用户：" + "openId" + "消息推送成功");
        } else {
            log.error("微信消息通知失败,errcode：{},errorMessage：{}", errorCode, errorMessage);
        }
    }

    /**
     * 获取acctoken
     *
     * @return
     */
    public String getAccessToken(Boolean flag) {
        Map<String, String> params = new HashMap<>();
        if(flag){
            params.put("APPID", appId);
            params.put("APPSECRET", secret);
        }else {
            params.put("APPID", mallAppId);
            params.put("APPSECRET", mallSecret);
        }
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(
                "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={APPID}&secret={APPSECRET}", String.class, params);
        String body = responseEntity.getBody();
        JSONObject object = JSON.parseObject(body);
        return object.getString("access_token");
    }

    /**
     * 消息体系组装
     *
     * @param openId      openId
     * @param remind      提醒信息
     * @param orderId     订单ID
     * @param name        用户姓名
     * @param orderStatus 订单状态
     * @param time        时间信息
     * @return WxMsgConfig实体信息
     */
    private WxMsgConfig getQRCodeMsgConfig(String openId, String remind, String orderId, String name, OrderStatus orderStatus, Long time) {
        // 基础数据添加。
        JSONObject jsonObject = new JSONObject();
        // 订单编号
        JSONObject characterStr = new JSONObject();
        characterStr.put("value", orderId);
        jsonObject.put("character_string1", characterStr);
        // 用户姓名
        JSONObject nameStr = new JSONObject();
        nameStr.put("value", name);
        jsonObject.put("name3", nameStr);

        JSONObject thing4Str = new JSONObject();
        thing4Str.put("value", "广东省");
        jsonObject.put("thing4", thing4Str);
        // 下单时间
        JSONObject timeStr = new JSONObject();
        timeStr.put("value", DateUtils.parseDateToStr("yyyy年MM月dd日 HH:mm", new Date()));
        jsonObject.put("date8", timeStr);
        // 提醒信息
        JSONObject remindStr = new JSONObject();
        remindStr.put("value", remind);
        jsonObject.put("thing2", remindStr);
        /**
         * 消息推送配置参数拼接
         */
        WxMsgConfig wxMsgConfig = new WxMsgConfig();
        // openId
        wxMsgConfig.setTouser(openId);
        // 模板id
        wxMsgConfig.setTemplate_id("Yd2PJIdgBhEadi3EkAGyS4DiFp1Rd5ErsEs_jEt-HX4");
        // 数据data
        wxMsgConfig.setData(jsonObject);
        return wxMsgConfig;

    }


    private WxMsgConfig buildMsgDto(String openId, WxMsgEnum wxMsgEnum, Map<String, Object> params) {
        // 基础数据添加。
        JSONObject jsonObject = new JSONObject();
        for (Map.Entry<String, Object> objectEntry : params.entrySet()) {
            JSONObject model = new JSONObject();
            model.put("value", objectEntry.getValue());
            jsonObject.put(objectEntry.getKey(), model);
        }
        /**
         * 消息推送配置参数拼接
         */
        WxMsgConfig wxMsgConfig = new WxMsgConfig();
        // openId
        wxMsgConfig.setTouser(openId);
        // 模板id
        wxMsgConfig.setTemplate_id(wxMsgEnum.getTempCode());
        // 数据data
        wxMsgConfig.setData(jsonObject);
        return wxMsgConfig;

    }

    /**
     * 发送请求
     *
     * @param url   http 推送url
     * @param param 消息体系信息
     * @return JSONObject实体信息
     */
    public JSONObject postData(String url, WxMsgConfig param) {
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(type);
        HttpEntity<WxMsgConfig> httpEntity = new HttpEntity<>(param, headers);
        return restTemplate.postForObject(url, httpEntity, JSONObject.class);
    }

    /**
     * 获取对应模板id
     *
     * @param orderStatus 订单状态
     * @return 模板ID
     */
    private String templateIdGet(OrderStatus orderStatus) {
        /**
         *     GOING_CANCEL(-2, "待上门时申请取消"),
         *     SERVER_CANCEL(-3, "服务中申请取消"),
         *     FINISH_CHECK_CANCEL(-4, "待确认时申请取消"),
         *     RECEIVE(0, "待接单"),
         *     PLAIN(1, "待排期"),
         *     GOING(2, "待上门"),
         *     SERVER(3, "服务中"),
         *     FINISH_CHECK(4, "待确认"),
         *     FINISH(5, "已完成"),
         *     CANCEL(6, "已取消");
         */
        switch (orderStatus) {
            case GOING_CANCEL:
                // 待上门时申请取消
                return "12";
            case SERVER_CANCEL:
                // 服务中申请取消
                return "12";
            case FINISH_CHECK_CANCEL:
                // 待确认时申请取消
                return "12";
            case RECEIVE:
                // 待接单
                return "12";
            case PLAIN:
                // 待排期
                return "12";
            case GOING:
                // 待上门
                return "12";
            case SERVER:
                // 服务中
                return "12";
            case FINISH_CHECK:
                // 待确认
                return "12";
            case FINISH:
                // 已完成
                return "12";
            default:
                // 已取消
                return "2";
        }
    }
}
