package cn.newfeifan.mall.module.pay.service.fuyouorder;

import cn.newfeifan.mall.framework.common.exception.ErrorCode;
import cn.newfeifan.mall.framework.pay.core.client.PayClient;
import cn.newfeifan.mall.module.pay.api.refund.dto.PayRefundCreateReqDTO;
import cn.newfeifan.mall.module.pay.dal.dataobject.channel.PayChannelDO;
import cn.newfeifan.mall.module.pay.dal.dataobject.order.PayOrderDO;
import cn.newfeifan.mall.module.pay.dal.dataobject.order.PayOrderExtensionDO;
import cn.newfeifan.mall.module.pay.dal.dataobject.refund.PayRefundDO;
import cn.newfeifan.mall.module.pay.dal.mysql.order.PayOrderExtensionMapper;
import cn.newfeifan.mall.module.pay.dal.mysql.refund.PayRefundMapper;
import cn.newfeifan.mall.module.pay.dal.redis.no.PayNoRedisDAO;
import cn.newfeifan.mall.module.pay.enums.fuyouorder.AfterSaleOrderTypeEnum;
import cn.newfeifan.mall.module.pay.enums.notify.PayNotifyTypeEnum;
import cn.newfeifan.mall.module.pay.enums.order.PayOrderStatusEnum;
import cn.newfeifan.mall.module.pay.enums.refund.PayRefundStatusEnum;
import cn.newfeifan.mall.module.pay.fuiou.reqdata.CommonQueryDataReq;
import cn.newfeifan.mall.module.pay.fuiou.reqdata.RefundDataReq;
import cn.newfeifan.mall.module.pay.fuiou.respVO.FuYouPayRefundResponse;
import cn.newfeifan.mall.module.pay.fuiou.respVO.FuYouQueryPayOrderResponseVO;
import cn.newfeifan.mall.module.pay.fuiou.util.DateUtils;
import cn.newfeifan.mall.module.pay.fuiou.util.FuiouHttpPoster;
import cn.newfeifan.mall.module.pay.fuiou.util.MD5;
import cn.newfeifan.mall.module.pay.service.notify.PayNotifyService;
import cn.newfeifan.mall.module.pay.service.order.PayOrderService;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.time.LocalDateTime;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.module.pay.enums.DictTypeConstants.*;
import static cn.newfeifan.mall.module.pay.enums.ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING;

@Slf4j
@Service
public class FuYouPayOrderServiceImpl implements FuYouPayOrderService {

    @Resource
    private PayNoRedisDAO noRedisDAO;

    @Resource
    private PayRefundMapper refundMapper;

    @Resource
    private PayOrderService orderService;

    @Resource
    private PayNotifyService notifyService;

    @Resource
    @Lazy
    private PayOrderService payOrderService;
    @Resource
    private PayOrderExtensionMapper orderExtensionMapper;

    @Override
    public void payRefund(PayRefundCreateReqDTO reqDTO, PayOrderDO order, PayRefundDO refund, PayChannelDO channel, PayClient client) {
        String no = noRedisDAO.generate(FUYOU_TRADE_ORDER_NO_PREFIX);

        FuiouHttpPoster http = new FuiouHttpPoster();
        http.setCharset("utf-8");
        http.setUrl("https://aipay.fuioupay.com/aggregatePay/commonRefund");
        RefundDataReq req = new RefundDataReq();
        req.setVersion(version);
        req.setMchnt_cd(mchnt_cd);
        req.setTerm_id(term_id);
        req.setRandom_str(DateUtils.getCurrentDate("yyyyMMddHHmmss")
                + "568974");
        req.setMchnt_order_no(order.getPayOrderNo());
        req.setRefund_order_no(no);
        req.setOrder_type(AfterSaleOrderTypeEnum.getType(order.getChannelCode()));
        req.setTotal_amt(order.getPrice().toString());
        req.setRefund_amt(refund.getRefundPrice().toString());
        StringBuilder sb = new StringBuilder();
        sb.append(req.getMchnt_cd()).append("|").append(req.getOrder_type()).append("|")
                .append(req.getMchnt_order_no()).append("|").append(req.getRefund_order_no())
                .append("|").append(req.getTotal_amt()).append("|").append(req.getRefund_amt())
                .append("|").append(req.getTerm_id()).append("|").append(req.getRandom_str())
                .append("|").append(req.getVersion()).append("|").append(privateKey);
        System.out.println("请求sign："+ sb);
        req.setSign(MD5.MD5Encode(sb.toString(), "UTF-8"));
        log.info("向富友发起退款请求 == 请求体：{}", JSON.toJSONString(req));
        try {
            String res = http.newPost(JSON.toJSONString(req));
            log.info("向富友发起退款请求 == 响应体：{}", res);

            // 解析返回结果,获取参数
            ObjectMapper mapper = new ObjectMapper();
            FuYouPayRefundResponse resp = mapper.readValue(res, FuYouPayRefundResponse.class);

            // 创建退款单
            PayRefundDO updateRefundObj = new PayRefundDO()
                    .setChannelRequest(JSON.toJSONString(req))
                    .setChannelResponse(res);

            // 记录异常信息
            if (!resultCode.equals(resp.getResult_code())) {
                updateRefundObj.setChannelErrorCode(resp.getResult_code());
                updateRefundObj.setChannelErrorMsg(resp.getResult_msg());
                refundMapper.updateById(updateRefundObj);

                if(resp.getResult_msg().contains("余额不足")){
                    throw exception(new ErrorCode(1_007_901_006, "{退款账户余额不足,请联系平台!!!}"));
                }

                ErrorCode ERROR = new ErrorCode(1_007_901_006, "请求退款失败");
                throw exception(ERROR);
            }

            // 1 更新 PayRefundDO
            updateRefundObj.setPayRefundNo(no)
                    .setSuccessTime(LocalDateTime.now())
                    .setChannelRefundNo(resp.getRefund_id())
                    .setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
            int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
            if (updateCounts == 0) { // 校验状态，必须是等待状态
                throw exception(REFUND_STATUS_IS_NOT_WAITING);
            }
            log.info("[notifyRefundSuccess][退款订单({}) 更新为退款成功]", refund.getId());

            // 2. 更新订单
            orderService.updateOrderRefundPrice(refund.getOrderId(), refund.getRefundPrice());

            // 3. 插入退款通知记录
            notifyService.createPayNotifyTask(PayNotifyTypeEnum.REFUND.getType(),
                    refund.getId());

        } catch (Exception e) {
            log.error("向富友发起退款请求 == 异常：{}", e.getMessage());
            ErrorCode ERROR = new ErrorCode(1_007_901_006, "退款错误!" + e.getMessage());
            throw exception(ERROR);
        }
    }

    @Override
    public PayOrderDO getPayOrderByStatus(PayOrderExtensionDO payOrderExtensionDO, PayOrderDO payOrder) {

        // 用一个新的对象接收，避免修改原对象
        PayOrderDO payOrderDO = payOrderService.getOrder(payOrder.getId());

        FuiouHttpPoster http = new FuiouHttpPoster();
        http.setCharset("utf-8");
        http.setUrl("https://aipay.fuioupay.com/aggregatePay/commonQuery");
        CommonQueryDataReq req = new CommonQueryDataReq();
        req.setVersion("1.0");
        req.setMchnt_cd(mchnt_cd);
        req.setRandom_str(DateUtils.getCurrentDate("yyyyMMddHHmmss")
                + "568974");
        req.setOrder_type(payOrderExtensionDO.getChannelCode());
        req.setMchnt_order_no(payOrderDO.getPayOrderNo());
        req.setTerm_id(term_id);
        String data = MD5.MD5Encode(req.getMchnt_cd() + "|" + req.getOrder_type() + "|" +
                req.getMchnt_order_no() + "|" + req.getTerm_id() + "|" + req.getRandom_str() + "|" +
                req.getVersion() + "|" + privateKey);
        req.setSign(data);

        String res;
        try {
            res = http.newPost(JSON.toJSONString(req));

            ObjectMapper mapper = new ObjectMapper();
            FuYouQueryPayOrderResponseVO resp = mapper.readValue(res, FuYouQueryPayOrderResponseVO.class);

            // 当响应结果为000000且交易状态为SUCCESS时才是支付成功
            if (resp.getResult_code().equals(resultCode) && resp.getTrans_stat().equals(transStatus)) {
                // 修改订单扩展信息
                payOrderExtensionDO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());

                // 修改订单信息
                payOrderDO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
                payOrderDO.setExtensionId(payOrderExtensionDO.getId());
                payOrderDO.setNo(payOrderExtensionDO.getNo());
                payOrderDO.setChannelOrderNo(resp.getTransaction_id());
                payOrderDO.setChannelUserId(resp.getBuyer_id());
                payOrderDO.setChannelId(payOrderExtensionDO.getChannelId());
                payOrderDO.setChannelCode(payOrderExtensionDO.getChannelCode());

                payOrderService.updatePayOrder(payOrderDO);
            } else {
                // 否则支付失败, 记录错误信息
                payOrderExtensionDO.setChannelErrorCode(resp.getResult_code());
                payOrderExtensionDO.setChannelErrorMsg(resp.getResult_msg());

            }
            payOrderExtensionDO.setChannelNotifyData(res);
            orderExtensionMapper.updateById(payOrderExtensionDO);

        } catch (Exception e) {
            ErrorCode ERROR = new ErrorCode(1_007_901_006, "查询支付订单失败");
            throw exception(ERROR);
        }

        return payOrderDO;
    }
}
