package com.chaozhanggui.system.lkl.service;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.template.TemplateException;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.chaozhanggui.common.system.config.MsgException;
import com.chaozhanggui.common.system.util.DateUtils;
import com.chaozhanggui.system.lkl.model.*;
import com.chaozhanggui.system.lkl.util.HtmlUtil;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;

@Service
public class MerchantLklService {

    private static final Logger log= LoggerFactory.getLogger(MerchantLklService.class);
    public static final String userNo = "22265868";


    private static final String client_id = "chaozhanggui";
    private static final String client_secret = "Y54Gqy6aLpxld3dp";
    private static final String grant_type = "client_credentials";


    //商户进件地址
    private static final String tuoKeMerchat = "https://htkactvi.lakala.com/registration/merchant";



    //进件接口
    public JSONObject merchantAduit(MerchantBaseInfoVO merchantBaseInfo, MerchantChannelStatusVO merchantChannelStatusVO
    , ConcurrentMap<String, RegionLklVO> regionLklVOConcurrentMap, AccountVO accountVO, BankCardVO bankCardVO,IdCardVO idCardVO
    ,ConcurrentMap<String,MerchantImageVO> imageVOConcurrentMap,MccReflectVO mccReflectVO,BankBranchLklVO bankBranchLklVO,
           BankRegionLklVO parentCode,BankRegionLklVO bankParentCode
                                    ) throws Exception {

        MsgException.checkNull(merchantBaseInfo,"商户基本信息不存在");
        MsgException.checkNull(merchantChannelStatusVO,"商户未提交审核");
        if (merchantChannelStatusVO.getStatus().equals(MerchantChannelStatusVO.AUDIT_STATUS_EXAMINING) && !merchantChannelStatusVO.getStatus().equals(MerchantChannelStatusVO.AUDIT_THIRD_STATUS_WAITING)) {
            MsgException.throwException("进件审核中，请等待审核结果");
        }

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

        MsgException.checkNull(regionLklVOConcurrentMap,"商户地址信息不存在");
        MsgException.checkNull(regionLklVOConcurrentMap.get("provinceCode"),"商户省份信息不存在");
        MsgException.checkNull(regionLklVOConcurrentMap.get("cityCode"),"商户城市信息不存在");
        MsgException.checkNull(regionLklVOConcurrentMap.get("countyCode"),"商户区县细信息不存在");
        MsgException.checkNull(accountVO,"商户结算信息未提交");
        MsgException.checkNull(bankCardVO,"商户结算卡信息未提交");
        MsgException.checkNull(idCardVO,"商户基本信息不完整");
        MsgException.checkNull(imageVOConcurrentMap,"商户基本信息不完整");
        MsgException.checkNull(imageVOConcurrentMap.get("BUSINESS_LICENCE"),"商户基本信息不完整");
        MsgException.checkNull(bankBranchLklVO,"结算卡对应的分行支行信息不存在");

        JSONObject object1 = new JSONObject();
        JSONObject object2 = new JSONObject();
        object1.put("userNo", userNo); //合作机构信息 由拓客SAAS提供
        object1.put("email", "chaozhanggui2023@163.com"); //商户邮箱
        object1.put("busiCode", "KLYX");//业务类型 BPOS:传统POS, ZPOS:电签,ZPOS4G：4G电签,SUPER_POS:智能pos,B_WIZARD:蓝精灵,PAPER_CODE:码牌,WECHAT_PAY:专业化扫码,KLYX:云音箱,QRCODE:收款王,MONEY_BOX:收钱宝盒根据业务开放取值
        object1.put("merRegName", merchantBaseInfo.getAlias()); //商户注册名称 不能少于七个中文
        object1.put("merType", (merchantBaseInfo.getMerchanttype().equals(1) || merchantBaseInfo.getMerchanttype().equals("2")) ? "TP_PERSONAL" : "TP_MERCHANT");  //商户注册类型 TP_MERCHANT:企业 TP_PERSONAL:⼩微个⼈
        object1.put("merName", merchantBaseInfo.getAlias()); //商户名称(经营名称)  不能少于七个中文
        object1.put("merAddr", merchantBaseInfo.getAddress()); //去掉省，市区后的详细地址
        object1.put("provinceCode", regionLklVOConcurrentMap.get("provinceCode").getCode()); //省代码 通过【地区信息→获取地区查询】接口获取 对应 code字段
        object1.put("cityCode", regionLklVOConcurrentMap.get("cityCode").getCode()); // 市代码 通过【地区信息→获取地区查询】接口获取 对应 code字段
        object1.put("countyCode", regionLklVOConcurrentMap.get("countyCode").getCode()); // 区县代码 通过【地区信息→获取地区查询】接口获取 对应 code字段
        Set<Object> attchmentsVoSet = new HashSet<>();

        //企业进件必传资料
        if(merchantBaseInfo.getMerchanttype().equals("3")){
            conventIdCardTime(object1,attchmentsVoSet,merchantBaseInfo,idCardVO,bankCardVO,imageVOConcurrentMap.get("BUSINESS_LICENCE").getPicurl(),bankCardVO.getLicenseurl(),mccReflectVO);
        }

        object1.put("latitude", "108.94647"); //经度 进件所在地址经度
        object1.put("longtude", "34.34727"); //纬度 进件所在地址纬度
        object1.put("source", "APP");  //进件来源 APP: app H5: h5
        object1.put("businessContent", merchantBaseInfo.getMccname()); //商户经营内容
        object1.put("larName", idCardVO.getCertname()); //法⼈姓名
        object1.put("larIdType", "01"); //法⼈证件类型 01 身份证 暂时只支持身份证
        object1.put("larIdCard", idCardVO.getCertno()); //法⼈证件号码
        object1.put("larIdCardStart",  DateUtils.convertString(idCardVO.getCertstarttime())); //法⼈证件开始⽇期 格式yyyy-MM-dd
        object1.put("larIdCardEnd", DateUtils.convertString(idCardVO.getCertendtime())); //法⼈证件过期时间 格式yyyy-MM-dd
        object1.put("contactMobile", merchantBaseInfo.getContactmobile()); //商户联系⼈⼿机号码
        object1.put("contactName", merchantBaseInfo.getContactname()); //商户联系⼈姓名


        object1.put("openningBankCode", bankBranchLklVO.getBranchBankNo()); //结算账户开户⾏号 通过【银行列表查询】接口获取 对应 branchBankNo字段
        object1.put("openningBankName", bankBranchLklVO.getBranchBankName()); //结算账户开户⾏名称 通过【银行列表查询】接口获取 对应 branchBankName字段
        object1.put("clearingBankCode", bankBranchLklVO.getClearNo()); //结算账户清算⾏号 通过【银行列表查询】接口获取 对应 clearNo字段

        object1.put("settleProvinceCode", parentCode.getCode()); //结算信息省份名称 通过【地区信息→获取银行地区查询】接口获取 对应 code字段
        object1.put("settleProvinceName", parentCode.getName()); //结算信息省份代码 通过【地区信息→获取银行地区查询】接口获取 对应 name字段
        object1.put("settleCityCode", bankParentCode.getCode()); //结算信息城市名称 通过【地区信息→获取银行地区查询】接口获取 对应 code字段
        object1.put("settleCityName", bankParentCode.getName()); //结算信息城市代码 通过【地区信息→获取银行地区查询】接口获取 对应 name字段

        if("02".equals(accountVO.getSettletype())){
            AttchmentsVo opening_permit = new AttchmentsVo(); //图片set
            opening_permit.setId(laKaLaFileUpload(accountVO.getCertificateurl(), "LETTER_OF_AUTHORIZATION"));//对私非法人授权函
            opening_permit.setType("LETTER_OF_AUTHORIZATION");//对私非法人授权函
            attchmentsVoSet.add(opening_permit);
        }

        object1.put("accountNo", bankCardVO.getBankcardno()); //结算人银行卡号
        object1.put("accountName", bankCardVO.getBankholder()); //结算人账户名称
        object1.put("accountType", bankCardVO.getAccounttype().equals("01") ? "58" : "57"); //结算账户类型 57 对公 58 对私
        object1.put("accountIdCard", idCardVO.getCertno()); //结算⼈证件号码

        if (bankCardVO.getAccounttype().equals("2")) {
            //对公收银台照片
            AttchmentsVo checkstand_img = new AttchmentsVo();
            checkstand_img.setId(laKaLaFileUpload(idCardVO.getImgnegative(), "CHECKSTAND_IMG")); //收银台照片
            checkstand_img.setType("CHECKSTAND_IMG");//收银台照片
            attchmentsVoSet.add(checkstand_img);


            //门头照片
            MerchantImageVO image =imageVOConcurrentMap.get("SHOP_OUTSIDE_IMG");
            MsgException.checkNull(image, "门头照片不存在");

            AttchmentsVo shop_outside_img = new AttchmentsVo();
            shop_outside_img.setId(laKaLaFileUpload(image.getPicurl(), "SHOP_OUTSIDE_IMG"));//门头照片
            shop_outside_img.setType("SHOP_OUTSIDE_IMG");
            attchmentsVoSet.add(shop_outside_img);

            //商铺内部照片
            image =imageVOConcurrentMap.get("SHOP_INSIDE_IMG");
            MsgException.checkNull(image, "商铺内部照片不存在");
            AttchmentsVo shop_inside_img = new AttchmentsVo();

            shop_inside_img.setId(laKaLaFileUpload(image.getPicurl(), "SHOP_INSIDE_IMG"));//商铺内部照片
            shop_inside_img.setType("SHOP_INSIDE_IMG");
            attchmentsVoSet.add(shop_inside_img);
        }

        JSONArray array = new JSONArray();

        Set<FeesSetVo> feesSet = new HashSet<>();
        FeesSetVo w = new FeesSetVo();
        w.setFeeCode("WECHAT");
        w.setFeeValue(0.38d);
        array.add(w);

        FeesSetVo a = new FeesSetVo();
        a.setFeeCode("ALIPAY");
        a.setFeeValue(0.38d);
        array.add(a);

        FeesSetVo u = new FeesSetVo();
        u.setFeeCode("SCAN_PAY_SECOND");
        u.setFeeValue(0.38d);
        array.add(u);
        feesSet.add(w);
        feesSet.add(a);
        feesSet.add(u);

        object2.put("termNum", "1"); //终端数量 1-5 最⼤ 5个终端
        object2.put("fees", feesSet); //费率集合

        object2.put("mcc","12007");
//        object2.put("mcc", ObjectUtils.isEmpty(mccReflect) ? "7399" : mccReflect.getMccCode());  //商户MCC编号 通过 【商户类别查询→查询小类】接口获取 对应 code字段
        object2.put("activityId", "37"); //归属活动信息 由拓客SAAS分配
        object1.put("bizContent", object2); //业务扩展信息 参⻅ 业务扩展信息


        AttchmentsVo frontLegalPerson = new AttchmentsVo(); //图片set
        frontLegalPerson.setId(laKaLaFileUpload(idCardVO.getImgpositive(), "ID_CARD_FRONT"));//法人身份证图片地址
        frontLegalPerson.setType("ID_CARD_FRONT");//身份证正⾯
        attchmentsVoSet.add(frontLegalPerson);

        AttchmentsVo reverseLegalPerson = new AttchmentsVo();
        reverseLegalPerson.setId(laKaLaFileUpload(idCardVO.getImgnegative(), "ID_CARD_BEHIND")); //法人身份证图片地址
        reverseLegalPerson.setType("ID_CARD_BEHIND");//身份证反⾯
        attchmentsVoSet.add(reverseLegalPerson);


        object1.put("attchments", attchmentsVoSet); //附件信息集合 参⻅ 附件信息
        object1.put("settleType", "D1"); //结算类型 D0秒到 D1次日结算

        log.info("请求地址:{},请求参数:{},",tuoKeMerchat,object1);

        Map map = getToken();

        String  result = cn.hutool.http.HttpRequest.post(tuoKeMerchat)
                .header("Authorization", "bearer " + map.get("access_token")).header("content-type", "application/json")
                .body(object1.toString()).execute().body();
       log.info("拉卡拉返回的进件结果信息:{}",result);
       if(ObjectUtil.isEmpty(result)){
           return null;
       }
       return JSONObject.parseObject(result);
    }








    private void conventIdCardTime(JSONObject jsonObject,Set<Object> attchmentsVoSet,MerchantBaseInfoVO merchantBaseInfo,IdCardVO idCardVO,BankCardVO bankCardVO,String businessLicence,String openingPermit,MccReflectVO mccReflect) throws Exception{
        StringBuffer startSb = new StringBuffer();
        StringBuffer endSb = new StringBuffer();

        if (merchantBaseInfo.getBussauthstarttime().contains("年")) {
            startSb.append(merchantBaseInfo.getBussauthstarttime().substring(0, 4));
            startSb.append("-");
            startSb.append(merchantBaseInfo.getBussauthstarttime().substring(5, 7));
            startSb.append("-");
            startSb.append(merchantBaseInfo.getBussauthstarttime().substring(8, 10));
        } else {
            startSb.append(merchantBaseInfo.getBussauthstarttime());
        }

        if (ObjectUtil.isEmpty(merchantBaseInfo.getBussauthendtime()) || "长期".equals(merchantBaseInfo.getBuslictype())) {
            endSb.append("2099-12-31");
        } else {
            if (merchantBaseInfo.getBussauthendtime().contains("年")) {
                endSb.append(merchantBaseInfo.getBussauthendtime().substring(0, 4));
                endSb.append("-");
                endSb.append(merchantBaseInfo.getBussauthendtime().substring(5, 7));
                endSb.append("-");
                endSb.append(merchantBaseInfo.getBussauthendtime().substring(8, 10));
            } else {
                endSb.append(merchantBaseInfo.getBussauthendtime());
            }
        }

        jsonObject.put("licenseDtStart", startSb); //营业执照开始时间⼩微商户可不传， 其他必传，格式yyyy-MM-dd
        jsonObject.put("licenseDtEnd", endSb); //⼩微商户可不传， 其他必传，格式yyyy-MM-dd


        AttchmentsVo business_licence = new AttchmentsVo(); //图片set
        business_licence.setId(laKaLaFileUpload(businessLicence, "BUSINESS_LICENCE"));//营业执照
        business_licence.setType("BUSINESS_LICENCE");//营业执照
        attchmentsVoSet.add(business_licence);

        //开户许可证
        AttchmentsVo opening_permit = new AttchmentsVo(); //图片set

        opening_permit.setId(laKaLaFileUpload(openingPermit, "OPENING_PERMIT"));//开户许可证
        opening_permit.setType("OPENING_PERMIT");//开户许可证
        attchmentsVoSet.add(opening_permit);
        Map<String, Object> data = new HashMap<>();
        data.put("customerName", merchantBaseInfo.getMerchantname());
        data.put("licenseNo", merchantBaseInfo.getBussauthnum());
        data.put("legalName", idCardVO.getCertname());
        data.put("licenseName", merchantBaseInfo.getMerchantname());
        data.put("identityNo", idCardVO.getCertno());
        data.put("address", merchantBaseInfo.getProvince().concat(merchantBaseInfo.getCity()).concat(merchantBaseInfo.getDistrict()));
        data.put("receiveDetail", merchantBaseInfo.getProvince().concat(merchantBaseInfo.getCity()).concat(merchantBaseInfo.getDistrict()).concat(merchantBaseInfo.getAddress()));
        data.put("identityNoExpire", endSb);
        data.put("accountName", bankCardVO.getBankholder());
        data.put("accountIdCard", idCardVO.getCertno());
        data.put("accountNo", bankCardVO.getBankcardno());

        data.put("accountIdDtEnd", idCardVO.getCertendtime().equals("长期") ? "2099-12-31" : DateUtils.convertString(idCardVO.getCertendtime()));
        data.put("bankName", bankCardVO.getBankname());
        data.put("mail", "chaozhanggui2023@163.com");
        data.put("contactManName", bankCardVO.getPhone());
        data.put("channelType", ObjectUtils.isEmpty(mccReflect) ? "7399" : mccReflect.getMccCode());
        data.put("phone", bankCardVO.getPhone());
        data.put("agencyName", merchantBaseInfo.getMerchantname());
       //协议
        AttchmentsVo agree_ment = new AttchmentsVo(); //图片set
        agree_ment.setId(laKaLaFileUpload(HtmlUtil.createAgreementPicture(HtmlUtil.writeHtml(data)),"AGREE_MENT"));//协议
        agree_ment.setType("AGREE_MENT");//协议
        attchmentsVoSet.add(agree_ment);
    }





    @SneakyThrows
    public static String laKaLaFileUpload(String url1, String type) {
        String url = "https://htkactvi.lakala.com/registration/file/upload";
        Map<String, Object> params = new HashMap<>();
        URI uri = null;
        try {
            uri = new URI(url1);
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
        RestTemplate restTemplate1 = new RestTemplate();
        ResponseEntity<byte[]> exchange = restTemplate1.exchange(uri, HttpMethod.GET, null, byte[].class);
        MultipartFile file1 = new MockMultipartFile("file", exchange.getBody());
        File file = convert(file1);

        params.put("file", file);
        params.put("imgType", type);
        params.put("sourcechnl", "0");
        params.put("isOcr", "false");

        Map token = getToken();
        String result = HttpRequest.post(url)
                .header("Authorization", "bearer " + token.get("access_token"))
                .form(params).execute().body();
        Map parse = (Map) JSONArray.parse(result);
        log.info("拉卡拉图片上传返回信息:{}", result);
        return parse.get("url").toString();
    }


    @SneakyThrows
    public static String laKaLaFileUpload(File file, String type) {
        String url = "https://htkactvi.lakala.com/registration/file/upload";
        Map<String, Object> params = new HashMap<>();

        params.put("file", file);
        params.put("imgType", type);
        params.put("sourcechnl", "0");
        params.put("isOcr", "false");

        Map token = getToken();
        String result = HttpRequest.post(url)
                .header("Authorization", "bearer " + token.get("access_token"))
                .form(params).execute().body();
        Map parse = (Map) JSONArray.parse(result);
        log.info("拉卡拉图片上传返回信息:{}", result);
        return parse.get("url").toString();
    }


    public static File convert(MultipartFile multipartFile) throws IOException {
        InputStream inputStream = multipartFile.getInputStream();
        File file = File.createTempFile(ObjectUtil.isEmpty(multipartFile.getOriginalFilename()) ? System.currentTimeMillis() + "" : multipartFile.getOriginalFilename(), ".png");
        FileOutputStream outputStream = new FileOutputStream(file);
        byte[] buffer = new byte[1024];
        int bytesRead = 0;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        outputStream.close();
        file.deleteOnExit();
        return file;
    }

    public static Map getToken() {
        RestTemplate client = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        // 表单提交
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.set("Authorization", "Basic " + getBase64());
        //  封装参数
        MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
        params.add("grant_type", grant_type);
        params.add("client_id", client_id);
        params.add("client_secret", client_secret);
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(params, headers);
        //  执行HTTP请求
        ResponseEntity<String> response = client.exchange("https://tkapi.lakala.com/auth/oauth/token", HttpMethod.POST, requestEntity, String.class);

        Map map = (Map) JSONArray.parse(response.getBody());
        return map;
    }




    public static String getBase64() {



        String encodeBase64String = org.apache.commons.codec.binary.Base64.encodeBase64String((client_id + ":" + client_secret).getBytes());

        return encodeBase64String;
    }


}
