package com.iformall.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.IdWorker;
import com.iformall.common.ResultData;
import com.iformall.domain.dto.WxMerchantDto;
import com.iformall.domain.po.WxAppinfo;
import com.iformall.domain.po.WxMerchant;
import com.iformall.domain.po.WxPayAccount;
import com.iformall.domain.po.WxProfitSharingReceiver;
import com.iformall.domain.po.msg.WxMsgRecord;
import com.iformall.domain.vo.WxMerchantVo;
import com.iformall.enums.*;
import com.iformall.mapper.WxAppinfoMapper;
import com.iformall.mapper.WxMerchantMapper;
import com.iformall.mapper.WxPayAccountMapper;
import com.iformall.mapper.WxProfitSharingReceiverMapper;
import com.iformall.mq.MqBaseProducer;
import com.iformall.pay.WxPayment;
import com.iformall.pay.WxProfitSharing;
import com.iformall.pay.WxProfitSharingReceiverP;
import com.iformall.service.WxProfitSharingReceiverService;
import com.iformall.utils.BeanUtils;
import com.iformall.utils.DateUtils;
import com.iformall.utils.Utility;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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


@Service
public class WxProfitSharingReceiverServiceImpl implements WxProfitSharingReceiverService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    final JSONObject errorMap = JSON.parseObject("{" +
            "\"SYSTEMERROR\":{\"detail\":\"接口返回错误\",\"reason\":\"系统超时\",\"resolution\":\"系统异常，请用相同参数重新调用\"}," +
            "\"PARAM_ERROR\":{\"detail\":\"参数错误\\t\",\"reason\":\"请求参数未按指引进行填写\",\"resolution\":\"请求参数错误，请重新检查再调用分账接口\"}," +
            "\"INVALID_REQUEST\":{\"detail\":\"请求不合法\",\"reason\":\"参数中APPID或MCHID不存在等 \",\"resolution\":\"请重新检查再调用分账接口\"}," +
            "\"OPENID_MISMATCH \":{\"detail\":\"OPENID错误\",\"reason\":\"OPENID与APPID不匹配\",\"resolution\":\"请检查OPENID是否正确\"}," +
            "\"FREQUENCY_LIMITED \":{\"detail\":\"频率限制\",\"reason\":\"请求过多被频率限制\",\"resolution\":\"该笔请求未受理，请降低频率后原单重试\"}," +
            "\"NOAUTH  \":{\"detail\":\"无分账权限\",\"reason\":\"未开通分账权限\",\"resolution\":\"请先开通分账\"}," +
            "\"USER_NOTEXIST\":{\"detail\":\"分账接受方不存在\",\"reason\":\"分账接受方不存在\",\"resolution\":\"请确认分账接收方类型或者账号无误后重试\"}}");


    @Autowired
    WxProfitSharingReceiverMapper wxProfitSharingReceiverMapper;
    @Autowired
    WxAppinfoMapper wxAppinfoMapper;
    @Autowired
    WxPayAccountMapper wxPayAccountMapper;
    @Autowired
    WxMerchantMapper wxMerchantMapper;
    @Autowired
    private MqBaseProducer mqBaseProducer;

    @Override
    public PageInfo<WxProfitSharingReceiver> listAsPage(WxProfitSharingReceiver record, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxProfitSharingReceiverMapper.findList(record));
    }

    @Override
    public WxProfitSharingReceiver getById(Long id) {
        return wxProfitSharingReceiverMapper.selectById(id);
    }

    @Override
    public void saveOrUpdate(WxProfitSharingReceiver record) {
        if (record.getId() == null) {
            //record.setId(UUID.randomUUID().toString().replaceAll("-", ""));
            final IdWorker idWorker = IdWorker.get();
            record.setId(idWorker.nextId());
            wxProfitSharingReceiverMapper.insert(record);
        } else {
            wxProfitSharingReceiverMapper.updateById(record);
        }
    }

    @Override
    public void deleteById(Long id) {
        wxProfitSharingReceiverMapper.deleteById(id);
    }


    @Override
    public WxProfitSharingReceiver findReceiver(WxMerchant merchant) {
        WxProfitSharingReceiver receiver = new WxProfitSharingReceiver();
        receiver.setTenantId(merchant.getTenantId());
        receiver.setMerchantId(merchant.getId());
        receiver.setSharingType(EnumProfitSharingType.PROFIT_SHARING_TYPE_WECHAT.getCode());
        receiver.setStatus(EnumProfitSharingReceiverStatus.PROFIT_SHARING_RECEIVER_STATUS_VALID.getCode());
        return wxProfitSharingReceiverMapper.selectOne(new QueryWrapper(receiver));
    }


    @Override
    public ResultData addReceiver(WxMerchant merchant, WxProfitSharingReceiver receiver, List<WxProfitSharingReceiver> delList) {

        WxAppinfo appInfo = new WxAppinfo();
        appInfo.setTenantId(merchant.getTenantId());
        appInfo.setType(EnumAppType.C.getCode());

        appInfo = wxAppinfoMapper.findList(appInfo).get(0);
        WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId());

        receiver.setTenantId(merchant.getTenantId());
        receiver.setMerchantId(merchant.getId());
        receiver.setSharingType(EnumProfitSharingType.PROFIT_SHARING_TYPE_WECHAT.getCode());
        receiver.setId(IdWorker.get().nextId());
        Date date = new Date();
        receiver.setCreateTime(date);
        receiver.setUpdateTime(date);
        receiver.setStatus(EnumProfitSharingReceiverStatus.PROFIT_SHARING_RECEIVER_STATUS_VALID.getCode());
        receiver.setIsUse(EnumProfitSharingUse.APPLY.getCode());
        //passed from uplevel
        //receiver.setReceiverAccount(receiverParam.getReceiverAccount());
        //receiver.setReceiverComments(receiverParam.getReceiverComments());
        //receiver.setReceiverType(receiverParam.getReceiverType());
        //receiver.setTrueName(receiverParam.getTrueName());

        //添加分账账户
        WxProfitSharingReceiverP wxProfitSharingReceiverP = new WxProfitSharingReceiverP();
        wxProfitSharingReceiverP.setAppid(appInfo.getParentAppId());
        wxProfitSharingReceiverP.setMch_id(payAccount.getMchId());
        wxProfitSharingReceiverP.setSub_appid(appInfo.getAppId());
        wxProfitSharingReceiverP.setSub_mch_id(payAccount.getSubMchId());
        wxProfitSharingReceiverP.setNonce_str(Utility.generate32UUID());
        wxProfitSharingReceiverP.setSign_type("HMAC-SHA256");


        JSONObject receiverJSON = new JSONObject();
        receiverJSON.put("type", EnumProfitSharingReceiverType.getEnum(receiver.getReceiverType()).getMessage());
        receiverJSON.put("account", receiver.getReceiverAccount());
        receiverJSON.put("name", receiver.getTrueName());

        wxProfitSharingReceiverP.setReceiver(receiverJSON.toJSONString());
        String response;
        try {
            wxProfitSharingReceiverP.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(wxProfitSharingReceiverP), payAccount.getApiKey()));
            response = WxProfitSharing.addReceiver(BeanUtils.toStringMap(wxProfitSharingReceiverP));
        } catch (Exception e) {
            logger.error(ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getMessage() + e.getMessage());
            return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED, e.getMessage());
        }
        Map<String, String> returnMap = WxPayment.xmlToMap(response);
        String return_code = returnMap.get("return_code");
        if (!"SUCCESS".equals(return_code)) {
            logger.error(ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getMessage() + returnMap.get("return_msg"));
            return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getCode(), returnMap.get("return_msg"));
        }

        String result_code = returnMap.get("result_code");
        if (!"SUCCESS".equals(result_code)) {
            logger.error(ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getMessage() + returnMap.get("err_code_des"));
            return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getCode(), returnMap.get("err_code_des"));
        }

        if (!WxPayment.verifyNotifyHMAC(returnMap, payAccount.getApiKey())) {
            logger.error(ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getMessage() + "verifyNotifyHMAC");
            return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getCode(), ErrorCode.PROFIT_SHARING_RECEIVER_ADD_FAILED.getMessage());
        }

        wxProfitSharingReceiverMapper.insert(receiver);

        //添加成功才删除账户
        for (WxProfitSharingReceiver delReceiver : delList) {
            delReceiver(delReceiver, EnumMsgSend.MSG_SEND_NOT_IMMEDIATELY.getCode());
        }

        WxProfitSharingReceiver wxProfitSharingReceiver = new WxProfitSharingReceiver();
        wxProfitSharingReceiver.setMerchantId(receiver.getMerchantId());
        wxProfitSharingReceiver.setStatus(EnumProfitSharingReceiverStatus.PROFIT_SHARING_RECEIVER_STATUS_INVALID.getCode());

        int size = wxProfitSharingReceiverMapper.selectList(new QueryWrapper(receiver)).size();

        if (size == 0) {
            //发送添加短信
            sendMsgByType(EnumMsgModel.ADD_SHARING_ACCOUNT_NOTIFY_MERCHANT.getCode(), merchant.getId(), receiver.getReceiverAccount(), receiver.getTenantId());
        } else {
            //添加变更短信
            sendMsgByType(EnumMsgModel.UPDATE_SHARING_ACCOUNT_NOTIFY_MERCHANT.getCode(), merchant.getId(), receiver.getReceiverAccount(), receiver.getTenantId());
        }
        return new ResultData(returnMap);
    }

    private void sendMsgByType(Integer type, Long merchantId, String account, String tenantId) {
        WxMerchantDto wxMerchantDto = new WxMerchantDto();
        wxMerchantDto.setId(merchantId);
        List<WxMerchantVo> listCVo = wxMerchantMapper.findListCVo(wxMerchantDto);
        if (listCVo.isEmpty()) {
            logger.info("更新商户分账账户发短信时未找到商户:" + merchantId);
            return;
        }
        WxMerchantVo wxMerchant = listCVo.get(0);
        //商户手机号
        String phone = wxMerchant.getMerchantLinkPhone();
        if (StringUtils.isEmpty(phone)) {
            logger.info("商户联系人电话不存在不发送短信");
            return;
        }
        String time = DateUtils.getSystemTime("yyyy年MM月dd日HH时mm分");
        String merchantName = wxMerchant.getMerchantName();
        sendMsg(phone, account, merchantName, time, type, tenantId);

    }

    @Override
    public void sendMsg(String phone, String account, String merchant, String time, Integer modelType, String tenantId) {
        // 发送短信
        logger.info("》》》》》》》》》》》");
        logger.info("商户分账账户发送短信开始");
        logger.info("》》》》》》》》》》》");

        Map<String, String> msgReplaceMap = new HashMap();
        if (StringUtils.isNotEmpty(account)) {
            msgReplaceMap.put("account", account);

        }
        if (StringUtils.isNotEmpty(merchant)) {
            msgReplaceMap.put("merchant", merchant);

        }
        if (StringUtils.isNotEmpty(time)) {
            msgReplaceMap.put("time", time);
        }

        WxMsgRecord wxMsgRecord = new WxMsgRecord();
        wxMsgRecord.setMsgType(EnumMsgRecordType.SMS.getCode());
        wxMsgRecord.setModelType(modelType);
        wxMsgRecord.setReceiver(phone);
        wxMsgRecord.setTenantId(tenantId);
        wxMsgRecord.setDynamicContentMap(msgReplaceMap);
        mqBaseProducer.sendMessage(wxMsgRecord, EnumMsgMqTopic.DEFAULT.getCode(), EnumMsgMqTag.DEFAULT.getCode(), EnumMsgMqKey.DEFAULT.getCode());
        logger.info("》》》》》》》》》》》");
        logger.info("商户分账账户发送短信结束");
        logger.info("》》》》》》》》》》》");
    }

    @Override
    public ResultData delReceiver(WxProfitSharingReceiver receiver, Integer send) {
        WxAppinfo appInfo = new WxAppinfo();
        appInfo.setTenantId(receiver.getTenantId());
        appInfo.setType(EnumAppType.C.getCode());

        appInfo = wxAppinfoMapper.findList(appInfo).get(0);
        WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId());

        receiver = wxProfitSharingReceiverMapper.selectById(receiver.getId());

        if (receiver == null)
            return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getCode(), ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getMessage());

        //检查此接受者是否注册在同一个商场的别的商户下
        final WxProfitSharingReceiver receiverParam = receiver;
        WxProfitSharingReceiver params = new WxProfitSharingReceiver();
        params.setTenantId(receiver.getTenantId());
        params.setStatus(EnumProfitSharingReceiverStatus.PROFIT_SHARING_RECEIVER_STATUS_VALID.getCode());
        List<WxProfitSharingReceiver> receiverList = wxProfitSharingReceiverMapper.findList(params);
        if (receiverList.stream().anyMatch(r -> (
                r.getReceiverType().equals(receiverParam.getReceiverType()) &&
                        r.getReceiverAccount().equals(receiverParam.getReceiverAccount()) &&
                        r.getTrueName().equals(receiverParam.getTrueName()) &&
                        !r.getMerchantId().equals(receiverParam.getMerchantId())
        ))) {
            //还有别的商户使用这个账号,不从微信服务器申请删除
        } else {
            //删除分账账户从微信服务器
            WxProfitSharingReceiverP wxProfitSharingReceiverP = new WxProfitSharingReceiverP();
            wxProfitSharingReceiverP.setAppid(appInfo.getParentAppId());
            wxProfitSharingReceiverP.setMch_id(payAccount.getMchId());
            wxProfitSharingReceiverP.setSub_appid(appInfo.getAppId());
            wxProfitSharingReceiverP.setSub_mch_id(payAccount.getSubMchId());
            wxProfitSharingReceiverP.setNonce_str(Utility.generate32UUID());
            wxProfitSharingReceiverP.setSign_type("HMAC-SHA256");

            JSONObject receiverJSON = new JSONObject();
            receiverJSON.put("type", EnumProfitSharingReceiverType.getEnum(receiver.getReceiverType()).getMessage());
            receiverJSON.put("account", receiver.getReceiverAccount());

            wxProfitSharingReceiverP.setReceiver(receiverJSON.toJSONString());
            String response;
            try {
                wxProfitSharingReceiverP.setSign(WxPayment.createSignHMAC(BeanUtils.toStringMap(wxProfitSharingReceiverP), payAccount.getApiKey()));
                response = WxProfitSharing.delReceiver(BeanUtils.toStringMap(wxProfitSharingReceiverP));
            } catch (Exception e) {
                logger.error(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getMessage() + e.getMessage());
                return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED, e.getMessage());
            }
            Map<String, String> returnMap = WxPayment.xmlToMap(response);
            String return_code = returnMap.get("return_code");
            if (!"SUCCESS".equals(return_code)) {
                logger.error(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getMessage() + returnMap.get("return_msg"));
                return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getCode(), returnMap.get("return_msg"));
            }

            String result_code = returnMap.get("result_code");
            if (!"SUCCESS".equals(result_code)) {

                if (returnMap.get("err_code").contains("USER_NOT_EXIST")) {
                    receiver.setStatus(EnumProfitSharingReceiverStatus.PROFIT_SHARING_RECEIVER_STATUS_INVALID.getCode());
                    receiver.setUpdateTime(new Date());
                    wxProfitSharingReceiverMapper.updateById(receiver);
                }
                logger.error(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getMessage() + returnMap.get("err_code_des"));
                return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getCode(), returnMap.get("err_code_des"));
            }

            if (!WxPayment.verifyNotifyHMAC(returnMap, payAccount.getApiKey())) {
                logger.error(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getMessage());
                return new ResultData(ErrorCode.PROFIT_SHARING_RECEIVER_DEL_FAILED.getCode(), "verifyNotifyHMAC");
            }
        }

        receiver.setStatus(EnumProfitSharingReceiverStatus.PROFIT_SHARING_RECEIVER_STATUS_INVALID.getCode());
        receiver.setUpdateTime(new Date());
        wxProfitSharingReceiverMapper.updateById(receiver);

        //发送短信
        if (send.equals(EnumMsgSend.MSG_SEND_IMMEDIATELY.getCode())) {
            sendMsgByType(EnumMsgModel.DELETE_SHARING_ACCOUNT_NOTIFY_MERCHANT.getCode(), receiver.getMerchantId(), receiver.getReceiverAccount(), receiver.getTenantId());
        }

        return new ResultData();
    }

    @Override
    public ResultData updateReceiver(WxMerchant merchant, WxProfitSharingReceiver receiver) {

        WxProfitSharingReceiver oldReceiver = new WxProfitSharingReceiver();
        oldReceiver.setTenantId(merchant.getTenantId());
        oldReceiver.setMerchantId(merchant.getId());
        oldReceiver.setSharingType(EnumProfitSharingType.PROFIT_SHARING_TYPE_WECHAT.getCode());
        oldReceiver.setStatus(EnumProfitSharingReceiverStatus.PROFIT_SHARING_RECEIVER_STATUS_VALID.getCode());
        List<WxProfitSharingReceiver> delList = wxProfitSharingReceiverMapper.selectList(new QueryWrapper(oldReceiver));
        oldReceiver.setReceiverAccount(receiver.getReceiverAccount());
        oldReceiver.setReceiverType(receiver.getReceiverType());
        oldReceiver.setTrueName(receiver.getTrueName());
        oldReceiver = wxProfitSharingReceiverMapper.selectOne(new QueryWrapper(oldReceiver));

        if (oldReceiver == null) {
            return addReceiver(merchant, receiver, delList);
        } else {
            oldReceiver.setParameter(receiver.getParameter());
            oldReceiver.setUpdateTime(new Date());
            wxProfitSharingReceiverMapper.updateById(oldReceiver);
        }

        return new ResultData();
    }
}
