package com.clx.performance.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.clx.performance.config.MslAppConfig;
import com.clx.performance.config.MslPaymentConfig;
import com.clx.performance.constant.ActionConstants;
import com.clx.performance.dao.ThirdPartRequestLogDao;
import com.clx.performance.encryption.oldmsl.PayEncryptTools;
import com.clx.performance.encryption.oldmsl.PrivateKeyConfig;
import com.clx.performance.encryption.oldmsl.SystemCodeEnum;
import com.clx.performance.enums.PayUnitTypeEnum;
import com.clx.performance.enums.PerformanceResultEnum;
import com.clx.performance.enums.ThirdRequestTypeEnum;
import com.clx.performance.service.PaymentService;
import com.clx.performance.model.ThirdPartRequestLog;
import com.clx.performance.param.pc.payment.PayParam;
import com.clx.performance.param.pc.payment.PayUnitDTO;
import com.clx.performance.param.pc.payment.PayUserDTO;
import com.clx.performance.service.ThirdPartRequestLogService;
import com.google.gson.Gson;
import com.msl.common.dto.HttpDTO;
import com.msl.common.enums.ResultCodeEnum;
import com.msl.common.exception.ServiceSystemException;
import com.msl.common.result.Result;
import com.msl.common.utils.EncryptUtil;
import com.msl.common.utils.HttpUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.security.GeneralSecurityException;
import java.util.UUID;

import static com.clx.performance.enums.HttpEnum.PERFORMANCE_PAY_CLX_PAYMENT;

@Service
@Slf4j
@AllArgsConstructor
public class PaymentServiceImpl implements PaymentService {

    public static final String TRANSPORT_USER = "13403503399";
    public static final String TRANSPORT_KEY = "9Y1N5AUP8N2TI359";
    /** 转账回调地址 **/
    public static final String NOTIFY_URL = "/clx-performance/payment/notify/userPayNotify";

    /** 违约回调地址 **/
    public static final String NOTIFY_BROKER_URL = "/clx-performance/payment/notify/userPayBrokerContractNotify";

    @Autowired
    private final MslPaymentConfig mslPaymentConfig;

    @Autowired
    ThirdPartRequestLogDao thirdPartRequestLogDao;

    @Autowired
    ThirdPartRequestLogService thirdPartRequestLogService;

    /**
     * 钱包直接划账给钱包
     *
     * @param payDTO
     * @return
     */
    @Override
    public Result paymentWallet(PayParam payDTO) {
        /** 构建支付单元 **/
        PayUnitDTO payUnitDTO = PayUnitDTO.builder()
                .id(payDTO.getTradeId())
                .from(payDTO.getFrom())
                .to(payDTO.getTo())
                .figure(payDTO.getFigure())
                .type(PayUnitTypeEnum.RESIDUE_PAY.getCode())
                .timestamp(System.currentTimeMillis() / 1000)
                .remark(payDTO.getRemark()).build();
        /** 生成签名**/
        PayEncryptTools.sign(payUnitDTO, PrivateKeyConfig.privateKeyByte);

        /** 构建支付支付 ***/
        PayUserDTO payUserDTO = PayUserDTO.builder()
                .pwd(payDTO.getPwd())
                .system(SystemCodeEnum.PERFORMANCE_SERVICE.getCode())
                .userCode(payDTO.getFrom())
                .orderNo(payDTO.getTradeNo())
                .uuid(UUID.randomUUID().toString().replaceAll("-", ""))
                .notifyUrl(mslPaymentConfig.getNotifyhost() + NOTIFY_URL)
                .payUnitDTO(payUnitDTO).build();
        log.info("发起支付请求日志 {}", JSON.toJSONString(payUserDTO));
        Result<Object> notify = (Result<Object>) postRequest(mslPaymentConfig.getHost()+ PERFORMANCE_PAY_CLX_PAYMENT.getUrl(), JSON.toJSONString(payUserDTO));
        log.info("支付返回日志 {}", notify);
        if (notify == null || notify.getCode() != 0) {
            //FEGIN返回null
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, notify.getMsg());
        }
        return notify;
    }



    /**
     * 钱包直接划账给钱包（违约）
     *
     * @param payDTO
     * @return
     */
    @Override
    public Result paymentBreakContractWallet(PayParam payDTO) {
        /** 构建支付单元 **/
        PayUnitDTO payUnitDTO = PayUnitDTO.builder()
                .id(payDTO.getTradeId())
                .from(payDTO.getFrom())
                .to(payDTO.getTo())
                .figure(payDTO.getFigure())
                .type(PayUnitTypeEnum.RESIDUE_PAY.getCode())
                .timestamp(System.currentTimeMillis() / 1000)
                .remark(payDTO.getRemark()).build();
        /** 生成签名**/
        PayEncryptTools.sign(payUnitDTO, PrivateKeyConfig.privateKeyByte);

        /** 构建支付支付 ***/
        PayUserDTO payUserDTO = PayUserDTO.builder()
                .pwd(payDTO.getPwd())
                .system(SystemCodeEnum.PERFORMANCE_SERVICE.getCode())
                .userCode(payDTO.getFrom())
                .orderNo(payDTO.getTradeNo())
                .uuid(UUID.randomUUID().toString().replaceAll("-", ""))
                .notifyUrl(mslPaymentConfig.getNotifyhost() + NOTIFY_BROKER_URL)
                .payUnitDTO(payUnitDTO).build();
        log.info("发起支付请求日志 {}", payUserDTO);
        Result<Object> notify = (Result<Object>) postRequest(mslPaymentConfig.getHost()+ PERFORMANCE_PAY_CLX_PAYMENT.getUrl(), JSON.toJSONString(payUserDTO));
        log.info("支付返回日志 {}", notify);
        if (notify == null || notify.getCode() != 0) {
            //FEGIN返回null
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, notify.getMsg());
        }
        return notify;
    }


    /**
     * post请求
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Result<?> postRequest(String requestUrl, String param) {
        ThirdPartRequestLog log = ThirdPartRequestLog.builder()
                .requestId(UUID.randomUUID().toString())
                //应用编号 10000 默认诚联信
                .appNo(Long.valueOf(10000))
                .requestType(ThirdRequestTypeEnum.SEND.getCode())
                .action(ActionConstants.CLX_PAYMENT_PAY)
                .url(requestUrl)
                .requestContent(param)
                //状态: 0-请求中,1-成功,2-失败
                .status(0)
                .build();
        thirdPartRequestLogDao.saveEntity(log);
        return encryptPost(requestUrl, param, log.getId());
    }

    private Result<?> encryptPost(String url, String param, Integer httpLogId) {
        try {
            return HttpUtil.post(url, null,
                    EncryptUtil.buildDTO(TRANSPORT_USER, param, TRANSPORT_KEY, System.currentTimeMillis()))
                    .map(r -> JSON.parseObject(r, new TypeReference<HttpDTO>() {
                    }))
                    .peek(dto -> log.info("http请求返回------dto->{}", dto))
                    .mapTry(dto -> EncryptUtil.decrypt(dto.getData(), TRANSPORT_KEY))

                    .mapWithObj(new TypeReference<Result<Object>>() {
                    }, this::covertResult)
                    .peek(result -> thirdPartRequestLogService.updateResult(httpLogId, result))
//                    .filter(Result::succeed)
                    .orElseThrow();
        } catch (GeneralSecurityException e) {
            log.error("解密失败", e);
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "http 请求异常");
        }
    }

    private <T> Result<T> covertResult(String result, TypeReference<Result<T>> reference) {
        return new Gson().fromJson(result, reference.getType());
    }





}
