package com.chaozhanggui.admin.system.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chaozhanggui.admin.system.util.RSAUtils;
import com.chaozhanggui.admin.system.util.SignUtils;
import com.chaozhanggui.admin.system.util.StringUtil;
import com.chaozhanggui.common.system.config.MsgException;
import com.chaozhanggui.common.system.config.channel.SxfConfig;
import com.chaozhanggui.common.system.util.FileUtil;
import com.chaozhanggui.common.system.util.ParametersUtil;
import com.chaozhanggui.dao.system.dao.*;
import com.chaozhanggui.dao.system.entity.*;
import com.chaozhanggui.dao.system.entity.DTO.AccountDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author lyf
 */
@Service
@Slf4j
public class SxfMerchantAuditService extends BaseMerchantAuditService{

    @Resource
    private TbPlussMerchantBaseInfoMapper merchantBaseInfoMapper;
    @Resource
    private TbPlussMerchantChannelStatusMapper merchantChannelStatusMapper;
    @Resource
    private TbPlussMerchantAuditRecordMapper merchantAuditRecordMapper;
    @Resource
    private MerchantImageService merchantImageService;
    @Resource
    private SxfMccInfoService sxfMccInfoService;
    @Resource
    private RegionReflectService regionReflectService;
    @Resource
    private TbPlussIdCardMapper idCardMapper;
    @Resource
    private TbPlussBankCodeSxfMapper bankCodeSxfMapper;

    @Transactional(rollbackFor = Exception.class)
    public void merchantAudit(String userId, boolean isFailCheck) {
        //进件检测
        merchantAuditCheck(userId,isFailCheck);

        TbPlussMerchantBaseInfo merchantBaseInfo = merchantBaseInfoMapper.selectByUserId(userId);
        TbPlussMerchantChannelStatus mcs = merchantChannelStatusMapper.getByMerchantCode(merchantBaseInfo.getMerchantcode(),"1");
        JSONObject reqData = new JSONObject();

        // 判断是第一次进件是入驻修改，还是第一次进件
        String targetUrl;
        MsgException.checkNull(mcs, "商户未提交审核");

        String status = mcs.getStatus();
        String thirdStatus = mcs.getThirdstatus();
        String merchantId = mcs.getMerchantid();

        if (status.equals(TbPlussMerchantChannelStatus.AUDIT_STATUS_EXAMINING) && !thirdStatus.equals(TbPlussMerchantChannelStatus.AUDIT_THIRD_STATUS_WAITING)) {
            MsgException.throwException("进件审核中，请等待审核结果");
        }

        if (TbPlussMerchantChannelStatus.isAudited(mcs)) {
            MsgException.throwException("商户已进件成功，请勿重复进件");
        }

        if (StringUtils.isEmpty(merchantId)) {
            // 初次进件
            targetUrl = SxfConfig.SXF_MERCHANT_INCOME;
        } else {
            // 进件失败数据修改
            targetUrl = SxfConfig.SXF_UPADTE_MERCHANT_RZ;
            reqData.put("mno", merchantId);
        }

        // step 1、组合请求数据
        reqData.putAll(getMerchantAuditInfo(userId, merchantBaseInfo, mcs));
        reqData.put("callbackUrl", ParametersUtil.domain + "/api/auditCallback/sxf");
        //支付宝通道ID
        reqData.put("specifyALiPayChannel", ParametersUtil.alipayChannel);
        log.info("{}随行付进件参数{}", userId, JSON.toJSONString(reqData));

        // step 2、调取通用请求
        JSONObject resultMap = requestApi(targetUrl, reqData);
        // 请求成功, 验证签名
        try {
            checkSign(resultMap);
        } catch (Exception e) {
            MsgException.throwException(e.getMessage());
        }

        MsgException.checkUnequals(SxfConfig.SXF_SUCCESS_CODE, resultMap.get("code"), "进件失败，" + resultMap.get("msg"));

        // 业务成功
        JSONObject respData = resultMap.getJSONObject("respData");
        MsgException.checkUnequals(SxfConfig.SXF_SUCCESS_CODE, respData.get("bizCode"), "进件失败，" + respData.get("bizMsg"));

        Date date = new Date();

        String applicationId = respData.getString("applicationId");
        String mno = respData.getString("mno");

        mcs.setChannel(1);
        mcs.setUpdatetime(date);
        mcs.setMerchantcode(merchantBaseInfo.getMerchantcode());
        mcs.setStatus("1");
        mcs.setThirdstatus("");
        mcs.setCallbackstatus("0");
        mcs.setRemark("随行付审核中");
        mcs.setApplicationid(applicationId);
        mcs.setMerchantid(mno);

        TbPlussMerchantAuditRecord merchantAuditRecord = new TbPlussMerchantAuditRecord();
        merchantAuditRecord.setStatus("1");
        merchantAuditRecord.setMerchantcode(merchantBaseInfo.getMerchantcode());
        merchantAuditRecord.setChannel(1);
        merchantAuditRecord.setThirdstatus("");
        merchantAuditRecord.setMerchantid(mno);
        merchantAuditRecordMapper.insert(merchantAuditRecord);


        if (StringUtil.isNotEmpty(mcs.getId())) {
            merchantChannelStatusMapper.updateByPrimaryKeySelective(mcs);
        } else {
            // 保存进件信息
            merchantChannelStatusMapper.insertSelective(mcs);
        }
    }
    private JSONObject getMerchantAuditInfo(String userId, TbPlussMerchantBaseInfo merchantBaseInfo, TbPlussMerchantChannelStatus merchantChannelStatus) {
        // step 1、组合请求数据
        JSONObject reqData = new JSONObject();
        MsgException.checkBlank(merchantBaseInfo.getMerchanttype(), "请先填写商户资料");

        AccountDTO accountDTO = accountService.getAccount(userId);

        List<TbPlussMerchantImage> merchantChannelImgList = merchantImageService.getListOfMerch(userId, TbPlussAccount.CHANNEL_TYPE_D1);

        for (TbPlussMerchantImage merchantImage : merchantChannelImgList) {
            // 兼容老通道用户，切换通道后，没有相关的图片链接
            if (StringUtils.isEmpty(merchantImage.getPhotourl())) {
                imageUpload(merchantImage);
            }
        }

        combineMerchantBaseInfo(reqData, merchantBaseInfo);
        combineCommon(reqData);
        combineBankInfo(reqData, userId);
        // 添加添加账户类型判断，此处可能是图片驳回，故需要自己添加账号类型判断
        String actTyp = TbPlussBankCard.ACCOUNT_TYPE_CORPORATE.equals(accountDTO.getBankCard().getAccounttype()) ? "00" : "01";

        combineImage(reqData, merchantChannelImgList, actTyp, merchantBaseInfo.getMerchanttype());

        //  入驻图片修改，去掉不能传的参数
        if (merchantChannelStatus != null && TbPlussMerchantChannelStatus.AUDIT_STATUS_REVIEW_REJECT.equals(merchantChannelStatus.getStatus())) {
            reqData.remove("operationalType");
            reqData.remove("haveLicenseNo");
            reqData.remove("mecTypeFlag");
            reqData.remove("parentMno");
            reqData.remove("independentModel");
            reqData.remove("qrcodeList");
            reqData.remove("bankCardRates");
            reqData.remove("settleType");
            reqData.remove("clearTimeSts");
            reqData.remove("clearTime");
            reqData.remove("supportPayChannels");
            reqData.remove("supportTradeTypes");
            reqData.remove("activityType");
            reqData.remove("specifyWechatChannel");
            reqData.remove("specifyALiPayChannel");
            reqData.remove("onlineType");
            reqData.remove("onlineName");
            reqData.remove("onlineTypeInfo");
            reqData.remove("cprRegNmCn");
            reqData.remove("registCode");
            reqData.remove("licenseMatch");
            reqData.remove("orgCode");
            reqData.remove("taxRegNo");
            reqData.remove("businessLicStt");
            reqData.remove("businessLicEnt");
            reqData.remove("identityName");
            reqData.remove("identityTyp");
            reqData.remove("identityNo");
            reqData.remove("legalPersonLicStt");
            reqData.remove("legalPersonLicEnt");
            reqData.remove("actNm");
            reqData.remove("actTyp");
            reqData.remove("stmManIdNo");
            reqData.remove("accountLicStt");
            reqData.remove("accountLicEnt");
        }
        return reqData;
    }

    /**
     * 向随行付发送请求
     * @param url
     * @param reqData
     * @return
     */
    public JSONObject requestApi(String url, JSONObject reqData) {
        RestTemplate restTemplate = new RestTemplate();
        try {
            JSONObject paramMap = new JSONObject();
            paramMap.put("orgId", SxfConfig.ORG_ID);
            paramMap.put("reqId", UUID.randomUUID().toString().replaceAll("-", ""));
            paramMap.put("version", "1.0");
            paramMap.put("timestamp", DateFormatUtils.format(new Date(), "yyyyMMddHHmmss"));
            paramMap.put("reqData", reqData);
            paramMap.put("signType", "RSA");
            String signContent = SignUtils.getSignContent(paramMap);
            paramMap.put("sign", RSAUtils.sign(SxfConfig.PRIVATE_KEY, signContent));
            log.info("===================>【随行付】请求参数:{}<================",paramMap);

            ResponseEntity<JSONObject> responseEntity = restTemplate.postForEntity(url, paramMap, JSONObject.class);
            // 检查网络请求状态
            if (!HttpStatus.OK.equals(responseEntity.getStatusCode())) {
                throw new MsgException("请求失败，请求状态异常");
            }

            log.info("=============return_info============");
            if (responseEntity.getBody() != null) {
                log.info(responseEntity.getBody().toJSONString());
            }
            return responseEntity.getBody();
        } catch (Exception e) {
            e.printStackTrace();
            throw new MsgException("随行付接口异常");
        }
    }

    /**
     * 随行付验签
     * @param receiveData
     * @throws Exception
     */
    public void checkSign(JSONObject receiveData) throws Exception {
        if (receiveData == null || receiveData.getString("sign") == null) {
            throw new MsgException("未知数据");
        }

        String srcData = SignUtils.getSignContent(receiveData);
        boolean sign = RSAUtils.checkSign(SxfConfig.PUBLIC_KEY, srcData, receiveData.getString("sign"));
        if (!sign) {
            throw new IllegalArgumentException("商户入驻回调接口验签不通过");
        }
    }


    /**
     * @param merchantImage 上传图片信息
     *                      orgId  - 机构编号;
     *                      reqId   - 请求id, uuid;
     *                      pictureType - 照片类型;   具体类型参照随行付文档;
     *                      file - 图片文件, 文件格式为mutilpartfile, 文件名为file
     */
    public void imageUpload(TbPlussMerchantImage merchantImage) {

        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        byte[] bytes;

        try {
            bytes = FileUtil.url2Bytes(merchantImage.getPicurl());
        } catch (Exception e) {
            e.printStackTrace();
            throw new MsgException("图片读取失败");
        }
        ByteArrayResource contentsAsResource = new ByteArrayResource(bytes) {
            @Override
            public String getFilename() {
                return UUID.randomUUID().toString().replace("-", "") + ".jpg";
            }
        };
        paramMap.add("file", contentsAsResource);
        paramMap.add("orgId", SxfConfig.ORG_ID);

        paramMap.add("pictureType", imgTypeTransform(merchantImage.getPhotoType()));

        HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(paramMap, headers);
        RestTemplate restTemplate = new RestTemplate();
        JSONObject responseJson = restTemplate.postForObject(SxfConfig.SXF_MERCHANT_INCOME_PHOTO_UPLOAD, request, JSONObject.class);

        MsgException.checkNull(responseJson, "请求失败");
        log.info("upload response : {}", responseJson.toJSONString());

        MsgException.checkUnequals(SxfConfig.SXF_SUCCESS_CODE, responseJson.get("code"), "请求失败");

        JSONObject respData = responseJson.getJSONObject("respData");

        MsgException.checkNull(respData, "上传图片失败");

        MsgException.checkUnequals(SxfConfig.SXF_SUCCESS_CODE, respData.get("bizCode"), respData.getString("bizMsg"));

        Date date = new Date();

        merchantImage.setPhotourl(respData.getString("PhotoUrl"));
    }
    /**
     * 图片类型转换，源照片类型主要为乐刷定义的图片类型，参考MerchantImage
     *
     * @param imageType 图片类型
     * @return 对应通道的图片定义类型
     */
    public String imgTypeTransform(String imageType) {
        switch (imageType) {
            case TbPlussMerchantImage.IDCARD_FRONT:
                return TbPlussMerchantImage.IDCARD_FRONT;
            case TbPlussMerchantImage.IDCARD_BACK:
                return TbPlussMerchantImage.IDCARD_BACK;
            case TbPlussMerchantImage.SETTLE_IDCARD_FRONT:
                return TbPlussMerchantImage.SETTLE_IDCARD_FRONT;
            case TbPlussMerchantImage.SETTLE_IDCARD_BACK:
                return TbPlussMerchantImage.SETTLE_IDCARD_BACK;
            case TbPlussMerchantImage.BANK_CARD_BACK:
                return TbPlussMerchantImage.BANK_CARD_BACK;
            case TbPlussMerchantImage.BANK_CARD_FRONT:
                return TbPlussMerchantImage.BANK_CARD_FRONT;
            case TbPlussMerchantImage.BUSINESS_LICENSE:
                return TbPlussMerchantImage.BUSINESS_LICENSE;
            case TbPlussMerchantImage.ACCOUNT_PERMITS:
                return TbPlussMerchantImage.ACCOUNT_PERMITS;
            case TbPlussMerchantImage.NON_LEG_SETTLE_AUTH:
                return TbPlussMerchantImage.NON_LEG_SETTLE_AUTH;
            case TbPlussMerchantImage.SHOP_FRONT_DOOR:
                return TbPlussMerchantImage.SHOP_FRONT_DOOR;
            case TbPlussMerchantImage.CASH_DESK_PHOTO:
                return TbPlussMerchantImage.CASH_DESK_PHOTO;
            case TbPlussMerchantImage.STORE_INTERIOR_PHOTO:
                return TbPlussMerchantImage.STORE_INTERIOR_PHOTO;
            default:
                return TbPlussMerchantImage.OTHER;
        }
    }
    private void combineMerchantBaseInfo(Map<String, Object> map, TbPlussMerchantBaseInfo merchantBaseInfo) {
        String mcc = merchantBaseInfo.getMcc();
        TbPlussSxfMccInfo sxfMccInfo = sxfMccInfoService.getByMccCode(mcc);
        map.put("mecDisNm", merchantBaseInfo.getAlias());
        map.put("mblNo", merchantBaseInfo.getContactmobile());

        if (sxfMccInfo == null) {
            map.put("operationalType", "01");
        } else {
            // 判断经营类型
            switch (sxfMccInfo.getfMccType()) {
                case "线上":
                    //TODO 如果渠道判定魏线上则 onlineType onlineName为必填
                    map.put("operationalType", "02");
                    break;
                case "非盈利":
                    map.put("operationalType", "03");
                    break;
                case "缴费类":
                    map.put("operationalType", "04");
                    break;
                case "保险":
                    map.put("operationalType", "05");
                    break;
                case "私立院校":
                    map.put("operationalType", "06");
                    break;
                default:
                    map.put("operationalType", "01");
                    break;
            }
        }

        // 商户类型
        switch (merchantBaseInfo.getMerchanttype()) {
            case "1":
                map.put("haveLicenseNo", "01");
                map.put("actTyp", "01");
                break;
            case "2":
                map.put("haveLicenseNo", "02");
                map.put("registCode", merchantBaseInfo.getBussauthnum());
                map.put("cprRegNmCn", merchantBaseInfo.getBussauthname());
                break;
            case "3":
                map.put("haveLicenseNo", "03");
                map.put("registCode", merchantBaseInfo.getBussauthnum());
                map.put("cprRegNmCn", merchantBaseInfo.getBussauthname());
                map.put("licenseMatch", "00");
                break;
            default:
                throw new MsgException("未知商户类型");
        }
        map.put("mecTypeFlag", "00");

        map.put("cprRegAddr", merchantBaseInfo.getAddress());

        String province = merchantBaseInfo.getProvince();
        String city = merchantBaseInfo.getCity();
        String area = merchantBaseInfo.getDistrict();
        TbPlussRegionCodeSxf regionCodeSxf = regionReflectService.getSxfRegionCode(province, city, area);

        map.put("regProvCd", regionCodeSxf.getProvincecode());
        map.put("regCityCd", regionCodeSxf.getCitycode());
        map.put("regDistCd", regionCodeSxf.getAreacode());

        map.put("mccCd", mcc);
        map.put("csTelNo", merchantBaseInfo.getContactmobile());
    }

    private void combineCommon(Map<String, Object> map) {
        Map<String, Object> rateMap = new HashMap<>();
        List<Map<String, Object>> qrCodeList = new LinkedList<>();
        // 微信
        rateMap.put("rate", "0.38");
        rateMap.put("rateType", "01");
        qrCodeList.add(rateMap);
        // 支付宝
        rateMap = new HashMap<>();
        rateMap.put("rate", "0.38");
        rateMap.put("rateType", "02");
        qrCodeList.add(rateMap);
        // 银联小于1000
        rateMap = new HashMap<>();
        rateMap.put("rate", "0.40");
        rateMap.put("rateType", "06");
        qrCodeList.add(rateMap);
        // 银联大于1000
        rateMap = new HashMap<>();
        rateMap.put("rate", "0.6");
        rateMap.put("rateType", "07");
        qrCodeList.add(rateMap);

        map.put("qrcodeList", qrCodeList);
        // 03 T1  04 D1
        map.put("settleType", "04");
    }

    /**
     * 组合银行卡信息， 必须的在combineMerchantBaseInfo之后调用
     *
     * @param paramMap 组合的数据
     * @param userId   用户id
     */
    private void combineBankInfo(Map<String, Object> paramMap, String userId) {
        // 结算信息
        AccountDTO accountDTO = accountService.getRealAccount(userId);
        MsgException.checkNull(accountDTO, "请完善结算信息");

        // 实名信息
        TbPlussIdCard certIdCard = idCardMapper.selectCertByUserId(Integer.valueOf(userId),TbPlussIdCard.TYPE_CERT);

        TbPlussIdCard inChargeIdCard;

        if (TbPlussAccount.SETTLE_TYPE_MICRO_STORE.equals(accountDTO.getSettletype())) {
            // 小微商户 - 结算信息中的身份信息即商户负责人信息
            inChargeIdCard = accountDTO.getIdcard();
        } else {
            // 其他的负责人信息是法人信息
            inChargeIdCard = idCardMapper.getLegalIdCard(userId);
        }

        TbPlussBankCard bankCard = accountDTO.getBankCard();
        paramMap.put("identityName", inChargeIdCard.getCertname());
        paramMap.put("identityTyp", inChargeIdCard.getCerttype());
        paramMap.put("identityNo", inChargeIdCard.getCertno());


        if ("01".equals(paramMap.get("haveLicenseNo"))) {
            // 小微商户
            paramMap.put("stmManIdNo", certIdCard.getCertno());
            paramMap.put("actTyp", "01");
        } else {
            // 非小微商户，可以
            paramMap.put("actTyp", TbPlussBankCard.ACCOUNT_TYPE_CORPORATE.equals(bankCard.getAccounttype()) ? "00" : "01");

            if (accountDTO.getSettletype() == null) {
                throw new MsgException("缺少结算信息(若无填写结算信息界面，请更新app)");
            }

            TbPlussIdCard idCard = accountDTO.getIdcard();
            if (idCard == null) {
                idCard = certIdCard;
            }
            // 对私需要传递
            if ("01".equals(paramMap.get("actTyp"))) {
                paramMap.put("stmManIdNo", idCard.getCertno());
            }
        }

        paramMap.put("actNm", bankCard.getBankholder());
        paramMap.put("actNo", bankCard.getBankcardno());
        paramMap.put("accountLicStt", inChargeIdCard.getCertstarttime());
        paramMap.put("accountLicEnt", inChargeIdCard.getCertendtime());

        QueryWrapper<TbPlussBankCodeSxf> queryWrapper = new QueryWrapper<TbPlussBankCodeSxf>()
                .eq("cnaps_code", bankCard.getContactline());
        TbPlussBankCodeSxf bankCodeSxf = bankCodeSxfMapper.selectOne(queryWrapper);
        // 银行code
        paramMap.put("depoBank", bankCodeSxf.getBankCode());
        // 省份code
        paramMap.put("depoProvCd", bankCodeSxf.getProvinceCode());
        // 城市code
        paramMap.put("depoCityCd", bankCodeSxf.getCityCode());
        // 联行号
        paramMap.put("lbnkNo", bankCodeSxf.getCnapsCode());
    }

    private void combineImage(Map<String, Object> paramMap, List<TbPlussMerchantImage> merchantImageList, String actTyp, String merchantType) {
        for (TbPlussMerchantImage merchantImage : merchantImageList) {
            combineImage(paramMap, merchantImage, actTyp, merchantType);
        }
    }
    private void combineImage(Map<String, Object> paramMap, TbPlussMerchantImage merchantImage, String actTyp, String merchantType) {
        // 非小微商户，必须传营业执照
        switch (merchantImage.getPhotoType()) {
            case TbPlussMerchantImage.IDCARD_FRONT:
                // 法人身份证正面
                paramMap.put("legalPersonidPositivePic", merchantImage.getPhotourl());
                break;
            case TbPlussMerchantImage.IDCARD_BACK:
                paramMap.put("legalPersonidOppositePic", merchantImage.getPhotourl());
                break;
            case TbPlussMerchantImage.SETTLE_IDCARD_FRONT:
                if (TbPlussBankCard.ACCOUNT_TYPE_PRIVATE.equals(paramMap.get("actTyp"))) {
                    // 对私需要传结算人身份证
                    paramMap.put("settlePersonIdcardPositive", merchantImage.getPhotourl());
                }
                break;
            case TbPlussMerchantImage.SETTLE_IDCARD_BACK:
                if (TbPlussBankCard.ACCOUNT_TYPE_PRIVATE.equals(paramMap.get("actTyp"))) {
                    // 对私需要传结算人身份证
                    paramMap.put("settlePersonIdcardOpposite", merchantImage.getPhotourl());
                }
                break;
            case TbPlussMerchantImage.SHOP_FRONT_DOOR:
                paramMap.put("storePic", merchantImage.getPhotourl());
                break;
            case TbPlussMerchantImage.STORE_INTERIOR_PHOTO:
                paramMap.put("insideScenePic", merchantImage.getPhotourl());
                break;
            case TbPlussMerchantImage.ACCOUNT_PERMITS:
                if (!"01".equals(actTyp)) {
                    // 对公结算需传开户许可证
                    paramMap.put("openingAccountLicensePic", merchantImage.getPhotourl());
                }
                break;
            case TbPlussMerchantImage.BANK_CARD_FRONT:
                if ("01".equals(actTyp)) {
                    // 对私需要传银行卡
                    paramMap.put("bankCardPositivePic", merchantImage.getPhotourl());
                }
                break;
            case TbPlussMerchantImage.BUSINESS_LICENSE:
                if (!"1".equals(merchantType)) {
                    paramMap.put("licensePic", merchantImage.getPhotourl());
                }
                break;
            case TbPlussMerchantImage.NON_LEG_SETTLE_AUTH:
                // 对私 结算人与法人的身份证证件不一致时需要提交
                if (TbPlussBankCard.ACCOUNT_TYPE_PRIVATE.equals(paramMap.get("actTyp")) && !paramMap.get("identityNo").equals(paramMap.get("stmManIdNo"))) {
                    paramMap.put("letterOfAuthPic", merchantImage.getPhotourl());
                }
                break;
            default:
                break;
        }
    }
}
