package com.crm.pay.service.impl.pay;

import com.alibaba.fastjson.JSON;
import com.crm.pay.dao.repository.CustomInfoRepository;
import com.crm.pay.entity.callback.NganluongCallbackEntity;
import com.crm.pay.entity.nganluong.NganluongCheckOrderEntity;
import com.crm.pay.entity.nganluong.NganluongCreateEntity;
import com.crm.pay.entity.property.NganluongPropertyEntity;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.NganluongService;
import com.crm.pay.service.impl.base.BasePayServiceImpl;
import com.crm.rely.backend.core.constant.Constants;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.model.entity.finance.deposit.FinanceDepositAddEntity;
import com.crm.pay.entity.FinanceDepositCallbackUpdateEntity;
import com.crm.rely.backend.model.pojo.table.CustomInfoTable;
import com.crm.rely.backend.model.pojo.table.FinanceDepositTable;
import com.crm.rely.backend.model.pojo.table.SysRemittanceChannelTable;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.util.HttpUtil;
import com.crm.rely.backend.util.MD5Util;
import com.crm.rely.backend.util.XmlUtils;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jsoup.Connection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @program:
 * @description:
 * @author: houn
 * @create: 2020-12-05 18:22
 */
@Slf4j
@Service
public class NganluongServiceImpl extends BasePayServiceImpl implements NganluongService {
    @Autowired
    private FinanceDepositService balanceService;

    @Autowired
    private CustomInfoRepository customInfoRepository;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String pay(FinanceDepositAddEntity balanceSaveEntity) throws Exception {

        SysRemittanceChannelTable channel = getPayChannel(PayConstants.NGANLUONG_PAY_TYPE_KEY);
        NganluongPropertyEntity payProperty = getPayProperty(channel, NganluongPropertyEntity.class);
        balanceSaveEntity.setCurrency(channel.getCurrency());
//        balanceSaveEntity.setTransformCurrency(channel.getTransformCurrency());

        FinanceDepositTable balanceTable = balanceService.save(balanceSaveEntity, channel);

        String url = getUrl(balanceTable, payProperty);
        balanceTable.setFormUrl(url);
        
        return url;
    }

    /**
     * 回调处理数据
     *
     * @param callbackEntity
     * @throws ServiceException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callback(NganluongCallbackEntity callbackEntity) throws Exception {
        log.info(String.format("callback orderNo:%s,callback data:%s", callbackEntity.getOrderCode(), JSON.toJSONString(callbackEntity)));

        boolean flag = callbackEntity == null || Strings.isNullOrEmpty(callbackEntity.getToken()) || Strings.isNullOrEmpty(callbackEntity.getOrderCode());
        if (flag) {
            throw new ServiceException("fail");
        }

        NganluongCheckOrderEntity nganluongCheckOrderEntity = getNganluongCheckOrderEntity(callbackEntity);

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity = getFinanceDepositCallbackUpdateEntity(PayConstants.NGANLUONG_SUCCESS_STATUS,
                nganluongCheckOrderEntity.getOrder_code(),
                nganluongCheckOrderEntity.getTransaction_id(),
                nganluongCheckOrderEntity.getTransaction_status(),callbackEntity);

        /**
         * 更新数据
         */
        balanceService.updateCallback(balanceCallbackUpdateEntity);
    }

    private NganluongCheckOrderEntity getNganluongCheckOrderEntity(NganluongCallbackEntity callbackEntity) throws Exception {
        NganluongPropertyEntity payProperty = getPayProperty(PayConstants.NGANLUONG_PAY_TYPE_KEY, false, NganluongPropertyEntity.class);
        Map<String, String> paramMap = new HashMap<>(3);

        String merchantPassword = MD5Util.getMD5(payProperty.getMerchantPass());
        String checksum = MD5Util.getMD5(callbackEntity.getToken() + "|" + merchantPassword);

        paramMap.put("merchant_id", payProperty.getMerchantId());
        paramMap.put("checksum", checksum);
        paramMap.put("token", callbackEntity.getToken());

        Connection.Response response = HttpUtil.post(payProperty.getBaseUrl(), paramMap);

        String body = response.body();

        log.info("Nganluong order check :" + body);

        NganluongCheckOrderEntity nganluongCheckOrderEntity = JSON.parseObject(body, NganluongCheckOrderEntity.class);

        if (nganluongCheckOrderEntity == null || !PayConstants.NGANLUONG_SUCCESS_STATUS.equals(nganluongCheckOrderEntity.getError_code())) {
            throw new ServiceException("fail");
        }
        return nganluongCheckOrderEntity;
    }

    /**
     * 获取支付url
     *
     * @param balanceTable
     * @return
     * @throws ServiceException
     */
    private String getUrl(FinanceDepositTable balanceTable, NganluongPropertyEntity payProperty) throws ServiceException, IOException, DocumentException {

        CustomInfoTable customInfoTable = customInfoRepository.getFirstById(balanceTable.getCustomId());
        if (customInfoTable == null) {
            throw new ServiceException(Constants.USER_NOT_EXIST_ERROR);
        }
        Map<String, String> paramMap = new HashMap<>(14);

        String merchant_password = MD5Util.getMD5(payProperty.getMerchantPass());
        String accountName = balanceTable.getName();
        String email = customInfoTable.getEmail();
        String phone = customInfoTable.getPhone();

        paramMap.put("merchant_id", payProperty.getMerchantId());
        paramMap.put("merchant_password", merchant_password);
        paramMap.put("version", payProperty.getVersion());
        paramMap.put("function", payProperty.getFunction());
        paramMap.put("receiver_email", payProperty.getEmail());
        paramMap.put("order_code", balanceTable.getSerial() + "_" + balanceTable.getLogin());
        paramMap.put("total_amount", balanceTable.getTransformAmount().toString());
        paramMap.put("payment_method", payProperty.getPaymentMethod());
        paramMap.put("bank_code", balanceTable.getBankCode());
        paramMap.put("return_url", payProperty.getCallbackUrl());
        paramMap.put("buyer_fullname", accountName);
        paramMap.put("buyer_email", email);
        paramMap.put("buyer_mobile", phone);
        paramMap.put("cur_code", payProperty.getCurCode());
        Connection.Response response = HttpUtil.post(payProperty.getBaseUrl(), paramMap);

        String body = response.body();

        log.info("Nganluong order create :" + body);

        NganluongCreateEntity nganluongCreateEntity = getNganluongResultEntity(body);
        if (nganluongCreateEntity.getErrorCode() != null && !PayConstants.NGANLUONG_SUCCESS_STATUS.equals(nganluongCreateEntity.getErrorCode())) {
            throw new ServiceException(nganluongCreateEntity.getDescription());
        }

        return nganluongCreateEntity.getCheckoutUrl();

    }

    private static NganluongCreateEntity getNganluongResultEntity(String content) throws DocumentException {

        Document document = DocumentHelper.parseText(content);
        Element element = document.getRootElement();
        NganluongCreateEntity nganluongCreateEntity = new NganluongCreateEntity();
        nganluongCreateEntity.setCheckoutUrl(XmlUtils.getElements(element, "checkout_url").get(0).getText());
        nganluongCreateEntity.setDescription(XmlUtils.getElements(element, "description").get(0).getText());
        nganluongCreateEntity.setErrorCode(XmlUtils.getElements(element, "error_code").get(0).getText());
        nganluongCreateEntity.setTimeLimit(XmlUtils.getElements(element, "time_limit").get(0).getText());
        nganluongCreateEntity.setToken(XmlUtils.getElements(element, "token").get(0).getText());

        return nganluongCreateEntity;
    }
}
