package com.bcxin.ins.third.build.yangguang;

import com.alibaba.fastjson.JSON;
import com.bcxin.ins.third.build.yangguang.util.Base64Util;
import com.bcxin.ins.third.build.yangguang.util.Encryption;
import com.bcxin.ins.third.build.yangguang.util.GZipUtils;
import com.bcxin.ins.third.build.yangguang.yggc.Result;
import com.bcxin.ins.service.order.InsTransactionAPIService;
import com.bcxin.ins.service.order.PolicyService;
import com.bcxin.ins.core.entity.R;
import com.bcxin.ins.core.service.ComDeployConfigService;
import com.bcxin.ins.util.GlobalResources;
import com.bcxin.ins.util.IdWorker;
import com.bcxin.ins.vo.ConstProp;
import com.bcxin.ins.vo.DictConst;
import com.bcxin.ins.vo.OrderFormVo;
import com.bcxin.ins.vo.PolicyTransactionVo;
import com.bcxin.mybatisplus.toolkit.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Apple on 2017/6/26.
 */
@Service
public class YGGCServiceImpl implements YGGCService {
    @Autowired
    private PolicyService policyService;
    @Autowired
    private InsTransactionAPIService insTransactionService;

    private Logger logger = LoggerFactory.getLogger(YGGCServiceImpl.class);

    @Autowired
    private ComDeployConfigService comDeployConfigService;

    /**
     * 承保
     * @param p
     * @return
     */
    @Override
    public R underwriting(Map<String, Object> p) {
        //参数
//        Result r = null;
//        try {
//            //TODO 系统内部通过参数调用生成具体YGGC实体，以下使用demo
//            r = this.httpSend(JSON.toJSONString(YGGC.getDemo()));
//            if(r==null) return new R("参数异常",false);
//        } catch (Exception e) {
//            logger.error("承保接口异常", e);
//            return new R("承保接口异常",false);
//        }
        return new R("承保成功:",true);

    }

    /**
     * 保险公司提供的请求方式，保留
     *
     * 前置机测试环境外网地址（承保、批改、注销）（对外）：http://testservicebus.sinosig.com/WebContent/ServicebusService.do
     * serverName=BXBHW
     * requestMethod=BXBHW
     * sign=BXBHWbxbhw123wtf8Y59PMv1jlaqYJgPvj254yis68P(用户名BXBHW+密码bxbhw123+密钥wtf8Y59PMv1jlaqYJgPvj254yis68P)
     * 测试密钥key(请求报文加密，返回报文解密):BXBHWCXBXWFVCH5LK4N1UO76BJE20ZRA3S8
     *
     * 前置机测试环境外网地址（查询电子保单）（对外）：http://testservicebus.sinosig.com/WebContent/ServicebusService.do
     * serverName=BXBHW
     * requestMethod=BXBHWQUERY
     * sign=BXBHWbxbhw123wtf8Y59PMv1jlaqYJgPvj254yis68P(用户名BXBHW+密码bxbhw123+密钥wtf8Y59PMv1jlaqYJgPvj254yis68P)
     * 测试密钥key(请求报文加密，返回报文解密):BXBHWCXBXWFVCH5LK4N1UO76BJE20ZRA3S8
     *
     *
     * 前置机生产环境外网地址：http://servicebus.sinosig.com/WebContent/ServicebusService.do
     * serverName=BXBHW
     * requestMethod=BXBHW
     * sign=BXBHWbxbhw123wTm7o7wShvg2flBvboG3NUZNVyznnd(用户名+密码+密钥wTm7o7wShvg2flBvboG3NUZNVyznnd)
     * 生产密钥key(请求报文加密，返回报文解密):BXBHW8KZOLXVK7J72U7VRCGLAEUYOZNVA4J
     *
     * 前置机生产环境外网地址（查询电子保单）（对外）：http://servicebus.sinosig.com/WebContent/ServicebusService.do
     * serverName=BXBHW
     * requestMethod=BXBHWQUERY
     * sign=BXBHWbxbhw123wTm7o7wShvg2flBvboG3NUZNVyznnd(用户名BXBHW+密码bxbhw123+密钥wTm7o7wShvg2flBvboG3NUZNVyznnd)
     * 生产密钥key(请求报文加密，返回报文解密):BXBHW8KZOLXVK7J72U7VRCGLAEUYOZNVA4J
     *
     * 以下
     * 1.YG_GC_MSG_BODY_KEY指秘钥key
     * 2.YG_GC_MSG_HEAD_KEY指秘钥
     *
     * @param json
     * @return
     * @throws Exception
     */
    @Override
    @SuppressWarnings("null")
    public Result underwritingHttpSend(String json, String type) throws Exception{
        //在这里统一获取配置文件
        String url =  GlobalResources.map.get("YG_GC_URL").trim(); //请求的url
        String msg_body_key = GlobalResources.map.get("YG_GC_MSG_BODY_KEY").trim(); //
        String msg_head_key = GlobalResources.map.get("YG_GC_MSG_HEAD_KEY").trim(); //
        String server_name = GlobalResources.map.get("YG_GC_SERVER_NAME").trim(); //
        String request_method=null;

        if ("2".equals(type)) {//电子保单接口
            request_method= GlobalResources.map.get("BDYG_GC_REQUEST_METHOD").trim();

        }else {//核保接口
            request_method= GlobalResources.map.get("YG_GC_REQUEST_METHOD").trim();
        }
        String password = GlobalResources.map.get("YG_GC_PASSWORD").trim(); //
        if(url==null|| msg_body_key==null||msg_head_key==null||server_name==null||request_method==null||password==null) return null;
        logger.trace("参数列表："+url);
        logger.trace("msg_body_key："+msg_body_key);
        logger.trace("msg_head_key："+msg_head_key);
        logger.trace("server_name： "+server_name);
        logger.trace("request_method： "+request_method);
        logger.trace("password：  "+password);

        Map<String, Object> map= new HashMap();
        OutputStream outputStream = null;
        ObjectOutputStream objOutputStream = null;
        InputStream inputStream = null;
        ObjectInputStream objinputStream = null;
        HttpURLConnection httpURLConnection=null;
        byte[] iXMLData = null;
        try {
            //初始化参数
//			map = this.messageToMap(map,url,json,msg_body_key,msg_head_key);
            logger.info("发送报文为：-------------------------->"+json);
            String sstrXML = Encryption.authcodeEncode(json, msg_body_key);
            logger.trace("加密后的报文：-------------------------->"+sstrXML);
            byte[] dedata = sstrXML.getBytes("GBK");
            dedata= GZipUtils.compress(dedata); //压缩报文内容
            map.put("serverName", Encryption.authcodeEncode(server_name,msg_head_key));
            map.put("requestMethod", Encryption.authcodeEncode(request_method, msg_head_key));
            map.put("sign", Encryption.authcodeEncode(server_name + password + msg_head_key, msg_head_key));
            map.put("json", dedata);


            //初始化连接
            httpURLConnection=this.initServletClient(httpURLConnection,url);
            outputStream = httpURLConnection.getOutputStream();
            objOutputStream = new ObjectOutputStream(outputStream);
            objOutputStream.writeObject(map.toString());
            objOutputStream.flush();
            objOutputStream.close();
            outputStream.flush();
            outputStream.close();

            //请求完成，开始获取返回值
            inputStream = httpURLConnection.getInputStream();  //
            BufferedInputStream input = null; // 输入流,用于接收请求的数据
            byte[] buffer = new byte[2048]; // 数据缓冲区
            int count = 0; // 每个缓冲区的实际数据长度
            ByteArrayOutputStream streamXML = new ByteArrayOutputStream(); // 请求数据存放对象
            try {
                input = new BufferedInputStream(inputStream);
                while ((count = input.read(buffer)) != -1) {
                    streamXML.write(buffer, 0, count);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (input != null) {
                    try {
                        input.close();
                    } catch (Exception f) {
                        f.printStackTrace();
                    }
                }
            }
            iXMLData = streamXML.toByteArray(); // 得到一个byte数组,提供给平台
            httpURLConnection.disconnect();
        } catch (Exception e) {
            logger.error("阳光接口调用发生异常",e);
        }finally{
            if(inputStream!=null){
                inputStream.close();
            }
            if(outputStream!=null){
                outputStream.close();
            }
            if(objinputStream!=null){
                objinputStream.close();
            }
            if(httpURLConnection!=null){
                httpURLConnection.disconnect();
            }
        }

        byte[] resultStr = GZipUtils.decompress(iXMLData);
        String returnStr = new String(resultStr,"GBK");
        String returnStr1 = Encryption.authcodeDecode(returnStr, msg_body_key);
        Result r = JSON.parseObject(returnStr1, Result.class);
//        ERROR00028	操作类型为空
//        ERROR00206	交易码为空
//        ERROR00027	系统标识为空
//        ERROR00026	接入模式为空
//        ERROR00275	保单信息为空
//        ERROR00085	投保人个团属性不能为空
//        ERROR10001	 保单号已存在
//        ERROR00008	 保额为空
//        ERROR00009	保费为空
//        ERROR00053	保费为0
//        ERROR00007	产品代码为空
//        ERROR00047	被保人证件号过长，超过20
//        ERROR00046	投保人证件号过长，超过20
//        ERROR00044	业务归属机构为空
//        ERROR00014	单证对应流水未下发
//        ERROR00045	经办人代码为空
//        ERROR10023	主子表保额保费不一致
//        ERROR10016	协议归属机构下无此出单业务人，两者归属机构需一致
//        ERROR10024	费用跟单信息为维护
//        ERROR10014	本保单为倒签单。不可转入
//        ERROR00412	一次投保份数超过规定投保份数
//        ERROR00413	投保总份数超过规定投保份数
        logger.info("解析的结果为："+JSON.toJSONString(r));
        return r;
    }




    /**
     * 保险公司提供的请求方式，保留
     * @param httpURLConnection
     * @param urlStr
     * @return
     * @throws Exception
     */
    public HttpURLConnection initServletClient(HttpURLConnection httpURLConnection,String urlStr) throws Exception{
        URL url = null;
        url = new URL(urlStr);
        //获取连接
        httpURLConnection=(HttpURLConnection) url.openConnection();
        httpURLConnection.setUseCaches(false);// 设置不能设置缓存
        httpURLConnection.setDoInput(true);// 打开读写属性，默认为false
        httpURLConnection.setDoOutput(true);// 打开读写属性，默认为false
        httpURLConnection.setRequestMethod("POST");// 设置提交方式，默认为GET
        httpURLConnection.setAllowUserInteraction(true);
        httpURLConnection.setConnectTimeout(60000);
        httpURLConnection.setReadTimeout(60000);
        return httpURLConnection;
    }

    /**
     * 支付宝url，传入投保单号和支付金额，然后返回支付的url，调用的是阳光的地址
     * @param proposalNoP 支付单号 50个字符内 0-9a-zA-Z
     * @param sumPremiumP 总金额 20个字符内，精度 0.00
     * @return
     */
    public R payUrlZFB(String proposalNoP , String sumPremiumP) {
        //参数
        String payurl =  GlobalResources.map.get("YG_GC_PAY_URL").trim(); //请求的url
        String server_name = GlobalResources.map.get("YG_GC_SERVER_NAME").trim(); // 服务名
        if(payurl==null||server_name==null) return new R("本地参数配置不正确",false);

//      String url = "http://testservicebus.sinosig.com/WebContent/PayWithForNotSeeFeeEncrypt.action";  //测试url
//      String url = "http://servicebus.sinosig.com/WebContent/PayWithForNotSeeFeeEncrypt.action"; //生产url
        try {
            String serverName = Base64Util.encode(server_name, Base64Util.CHARSET_UTF8);
            String requestMethod = Base64Util.encode(server_name, Base64Util.CHARSET_UTF8);
            String proposalNo = Base64Util.encode(proposalNoP, Base64Util.CHARSET_UTF8); //投保单号，投保返回值
            String sysflag = Base64Util.encode(server_name, Base64Util.CHARSET_UTF8);
            String transCode = Base64Util.encode("SV000332", Base64Util.CHARSET_UTF8);  //交易码固定
            String sumPremium = Base64Util.encode(sumPremiumP, Base64Util.CHARSET_UTF8); //保费
            String pageFlag = Base64Util.encode("", Base64Util.CHARSET_UTF8);
            String payType = Base64Util.encode("ZFB", Base64Util.CHARSET_UTF8); //支付类型为支付宝
            payurl = payurl+"?"+"serverName="+serverName+"&requestMethod="+requestMethod+"&proposalNo="+proposalNo+"&sysflag="+sysflag
                    +"&transCode="+transCode+"&sumPremium="+sumPremium+"&pageFlag="+pageFlag+"&payType="+payType;
        } catch (Exception e) {
            logger.error("YGGC-ERROR-00001: 阳光支付宝url生成出错，投保单号："+proposalNoP,e);
            return new R("阳光支付宝url生成出错，投保单号："+proposalNoP,false);
        }
        logger.info(payurl);
        return new R(payurl,true);
    }

    @Override
    public boolean  policyYG_callbackPay(Result result){
        boolean flag;
        try {
            String policyNo=result.getTbResultList().get(0).getPolicyNo();;

            String proposalNo=result.getTbResultList().get(0).getProposalNo();


            OrderFormVo dto = policyService.getPolicyDtoByRcptNo(proposalNo);//根据投保单号获得订单号
            if (dto!=null){
                if (StringUtils.isEmpty(dto.getExternal_reference())) {
                    IdWorker idWorker = new IdWorker(ConstProp.INT_NUMBER_WORKERID, ConstProp.INT_NUMBER_ZERO);
                    PolicyTransactionVo pvo = new PolicyTransactionVo();
                    pvo.setTrade_serial_number(String.valueOf(idWorker.nextId()));//交易流水号
                    pvo.setPay_amount(new BigDecimal(dto.getGross_premium()));
                    pvo.setStart_time(new Date());
                    pvo.setEnd_time(new Date());
                    pvo.setPayment_method(ConstProp.DIGIT_ONE);
                    pvo.setPay_type(DictConst.PAY_TYPE_ZFB);
                    pvo.setPolicy_id(dto.getOid());
                    pvo.setTransaction_status(DictConst.PAY_STATUS_YZF);
                    pvo.setPath_sign(ConstProp.DIGIT_ONE);
                    pvo.setUser_id(Long.parseLong(dto.getUser_oid()));
                    insTransactionService.saveTransaction(pvo);
                    logger.info("支付接口回调-callbackPay：接收成功-支付信息处理完成");
                    //TODO 以下补充调承保查询接口
                    PolicyTransactionVo vo = new PolicyTransactionVo();
                    //保存保单号
                    vo.setPolicy_number(policyNo);//policy.setExternalReference();
                    vo.setPolicy_id(dto.getOid());
                    insTransactionService.savePolicyExternalReference(vo);
                }
                flag = true;
                logger.info("支付接口回调-callbackPay：接收成功-承保信息处理结果--------" + flag);
                logger.info("支付接口回调-callbackPay：接收成功-承保信息处理完成");
                logger.info("支付请求：" + result.toString());
            }else{
                logger.info("支付请求：找不到订单号");
                return false;
            }
        }catch (Exception e){
            logger.error("平安团意险支付回调过程事务发现异常，回滚数据",e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            flag = false;
        }
        return flag;
    }

}
