package com.yihu.wlyy.service.weixin.wxpay.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yihu.wlyy.entity.charge.WlyyCharge;
import com.yihu.wlyy.entity.organization.HospitalMapping;
import com.yihu.wlyy.entity.patient.Patient;
import com.yihu.wlyy.repository.charge.ChargeDao;
import com.yihu.wlyy.repository.organization.HospitalMappingDao;
import com.yihu.wlyy.repository.patient.PatientDao;
import com.yihu.wlyy.service.third.httplog.LogService;
import com.yihu.wlyy.service.weixin.wxpay.common.Configure;
import com.yihu.wlyy.service.weixin.wxpay.model.BindCard;
import com.yihu.wlyy.service.weixin.wxpay.model.Charge;
import com.yihu.wlyy.util.SystemConf;
import com.ylzinfo.onepay.sdk.OnepayDefaultClient;
import com.ylzinfo.onepay.sdk.domain.RequestParams;
import com.ylzinfo.onepay.sdk.domain.ResponseParams;
import com.ylzinfo.onepay.sdk.utils.DateUtil;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 易联众统一支付服务类
 * add by hzp at 20170523
 */
@Service
public class OnePayService {

    @Autowired
    private Configure config;

    @Autowired
    private LogService logService;

    private String signType= "MD5";
    private String encryptType= "AES";

    @Autowired
    private HospitalMappingDao hospitalMappingDao;

    @Autowired
    ObjectMapper objectMapper;

    @Autowired
    ChargeDao chargeDao;
    @Autowired
    PatientDao patientDao;

    /**
     *  查询绑卡信息
     */
    public BindCard bindCard(String patient,String openid)  throws Exception
    {
        BindCard card = bindCard(openid);

        //更新患者信息
        if(card!=null)
        {
            Patient p = patientDao.findByCode(patient);
            p.setOpenid(openid);
            p.setSsc(card.getCardNo());
            if(card.getIdType()=="01")      //身份证
            {
                p.setIdcard(card.getIdNo());
            }
            p.setName(card.getUserName());
            patientDao.save(p);
        }

        return card;
    }

    /**
     * 查询绑卡信息
     */
    private BindCard bindCard(String openid) throws Exception
    {
        Boolean isSuccess = true;
        String msgBody = "";
        String response = "";
        String error = "";
        BindCard result = null;

        String appId = config.getOnepayAppId();
        String appSecret = config.getOnepayAppSecret();
        OnepayDefaultClient onepayClient = new OnepayDefaultClient(config.getOnepayApi(),appId, appSecret, signType, encryptType);

        try {
            RequestParams requestParams = new RequestParams();
            requestParams.setAppId(appId);
            requestParams.setTimestamp(DateUtil.getCurrentDateTime());
            requestParams.setSignType(signType);
            requestParams.setEncryptType(encryptType);
            requestParams.setTimestamp(DateUtil.getCurrentDateTime());

            // 请求报文体参数，详见接口文档各接口——请求参数定义
            // 如医保绑卡信息请求参数
            JSONObject params = new JSONObject();
            params.put("openId", openid);
            params.put("accId", SystemConf.getInstance().getAppId());  //微信公众号开发者ID
            requestParams.setParam(params);
            requestParams.setTransType(config.getBindCardType());

            msgBody =  JSON.toJSONString(requestParams);
            ResponseParams<JSONObject> res = onepayClient.execute(requestParams);
            response =  JSON.toJSONString(res);

            // 如医保卡绑卡信息返回参数
            if (OnepayDefaultClient.isSuccessful(res)) {
                result = JSON.toJavaObject(res.getParam(), BindCard.class);

                //业务处理***********
                System.out.println("请求成功,返回参数:" + result.getCardNo() + "," +  result.getIdType() + "," + result.getIdNo() + "," + result.getUserName() + "," + result.getUserId());

            }
            else {
                isSuccess = false;
                error = "请求失败,返回结果:" + res.getRespCode() + "," + res.getRespMsg();
            }
        }
        catch (Exception ex) {
            isSuccess = false;
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            ex.printStackTrace(pw);
            error = sw.toString();
        }

        //保存http日志
        logService.saveHttpLog(isSuccess,config.getBindCardType(),"查询绑卡信息","POST",null,msgBody,response,error,logService.onepayType);

        if(!isSuccess)
        {
            throw new Exception(error);
        }

        return result;
    }

    /**
     * 家庭医生签约支付
     */
    public String charge(String orgCode,String chargeType,String chargeRelation,Integer totalAmount,Integer selfpayAmount,Integer insuranceAmount,String feeDetail,String patient,String openid) throws Exception
    {
        //获取机构映射
        HospitalMapping hos = hospitalMappingDao.findByCode(orgCode);
        if(hos==null)
        {
            throw new Exception("no hospital mapping!");
        }

        return charge(orgCode,hos.getName(),hos.getAppId(), hos.getAppSecret(), chargeType,chargeRelation,totalAmount, selfpayAmount, insuranceAmount, feeDetail,patient,openid);
    }

    /**
     * 家庭医生签约支付，成功则返回支付路径
     */
    private String charge(String orgCode,String orgName,String appId,String appSecret,String chargeType,String chargeRelation,Integer totalAmount,Integer selfpayAmount,Integer insuranceAmount,String feeDetail,String patient,String openid) throws Exception
    {
        Boolean isSuccess = true;
        String msgBody = "";
        String response = "";
        String error = "";
        String result = "";
        String channel = "WX_MMP";   //  医保支付渠道
        String subject = "家庭医生签约支付";   //  订单名称

        OnepayDefaultClient onepayClient = new OnepayDefaultClient(config.getOnepayApi(),appId, appSecret, signType, encryptType);

        WlyyCharge charge = new WlyyCharge();
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");

        charge.setChargeType(chargeType);   //交易类型
        charge.setChargeRelation(chargeRelation);  //交易关联代码
        charge.setCode(uuid);  //  接入应用支付业务流水号
        Date now = new Date();
        charge.setCreateTime(now);
        charge.setPatient(patient);     //  用户
        charge.setOpenid(openid);     //  用戶微信openid
        try {
            charge.setHospital(orgCode);
            charge.setHospitalName(orgName);
            charge.setChannel(channel);
            charge.setMerchName(orgName);
            charge.setSubject(subject);
            charge.setTotalAmount(totalAmount);  //  交易总金额
            charge.setSelfpayAmount(selfpayAmount);  //  自费金额
            charge.setInsuranceAmount(insuranceAmount);  //  医保支付金额
            charge.setFeeDetail(feeDetail);  //  费用明细

            BindCard card= bindCard(openid);
            String name = card.getUserName();
            String ssc = card.getCardNo();
            String idType = card.getIdType();
            String idNo = card.getIdNo();
            charge.setName(name);
            charge.setIdType(idType);
            charge.setIdNo(idNo);

            SimpleDateFormat formatter =   new SimpleDateFormat("yyyyMMddHHmmss");
            String currentDateTime = formatter.format(now);
            RequestParams requestParams = new RequestParams();
            requestParams.setAppId(appId);
            requestParams.setTimestamp(currentDateTime);
            requestParams.setSignType(signType);
            requestParams.setEncryptType(encryptType);
            requestParams.setTransType(config.getChargeType());

            //业务参数
            JSONObject params = new JSONObject();

            params.put("outChargeNo",uuid);  //接入应用结算业务流水号
            params.put("outChargeTime",currentDateTime);    //接入应用内结算时间
            params.put("userId",openid);   //用户 ID
            params.put("cardNo",ssc);   //医保卡号"D64775061"

            //获取绑卡信息
            params.put("userName",name);
            params.put("idType",idType);
            params.put("idNo",idNo);
            params.put("totalAmount",totalAmount);   //交易总金额
            params.put("selfpayAmount",selfpayAmount);   //自费金额
            params.put("insuranceAmount",insuranceAmount);   //医保支付金额
            params.put("returnUrl","https://mp.weixin.qq.com/insurance/pay/detail");   //页面跳转地址
            params.put("feeDetail",feeDetail);   //费用明细
            params.put("channel",channel);  //微信医保支付
            params.put("merchName",orgName);  //收款单位名称
            params.put("subject",subject);  //订单名称
            //params.put("wxToken","");


            //extendParams 扩展入参
            Map<String,String> map = new HashMap<>();
            map.put("feeType","04");//家庭医生签约
            map.put("settleType","02"); //健康账户支付
            params.put("requestContent",objectMapper.writeValueAsString(map));// 请求结构体
            requestParams.setParam(params);
            msgBody =  JSON.toJSONString(requestParams);
            //执行支付
            ResponseParams<JSONObject> res = onepayClient.execute(requestParams);
            response =  JSON.toJSONString(res);

            if (OnepayDefaultClient.isSuccessful(res)) {
                JSONObject json = res.getParam();
                String chargeNo = String.valueOf(json.get("chargeNo"));      //医保结算业务流水号
                result =  String.valueOf(json.get("payUrl"));
                charge.setTradeStatus("0");//交易状态0 成功 1 失败 2 已退款
                charge.setChargeNo(chargeNo);

            } else {
                charge.setTradeStatus("1");
                isSuccess = false;
                error = "请求失败,返回结果:" + res.getRespCode() + "," + res.getRespMsg();
            }
        } catch (Exception ex) {
            isSuccess = false;
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            ex.printStackTrace(pw);
            error = sw.toString();
        }

        //保存交易记录
        chargeDao.save(charge);

        //保存http日志
        logService.saveHttpLog(isSuccess,config.getChargeType(),"家庭医生签约支付","POST",null,msgBody,response,error,logService.onepayType);

        if(!isSuccess)
        {
            throw new Exception(error);
        }

        return result;
    }

    /**
     * 家庭医生签约支付查询
     */
    public Charge chargeQuery(String code) throws Exception
    {
        Boolean isSuccess = true;
        String msgBody = "";
        String response = "";
        String error = "";
        Charge result = null;

        String appId = config.getOnepayAppId();
        String appSecret = config.getOnepayAppSecret();
        OnepayDefaultClient onepayClient = new OnepayDefaultClient(config.getOnepayApi(),appId, appSecret, signType, encryptType);
        try {
            RequestParams requestParams = new RequestParams();
            requestParams.setAppId(appId);
            requestParams.setTimestamp(DateUtil.getCurrentDateTime());
            requestParams.setSignType(signType);
            requestParams.setEncryptType(encryptType);
            requestParams.setTimestamp(DateUtil.getCurrentDateTime());
            requestParams.setTransType(config.getChargeQueryType());

            //业务参数
            JSONObject params = new JSONObject();
            params.put("outChargeNo",code);  //接入应用结算业务流水号

            requestParams.setParam(params);
            msgBody =  JSON.toJSONString(requestParams);
            //执行支付
            ResponseParams<JSONObject> res = onepayClient.execute(requestParams);
            response =  JSON.toJSONString(res);

            if (OnepayDefaultClient.isSuccessful(res)) {
                result = JSON.toJavaObject(res.getParam(),Charge.class);

                //业务处理*******************
                System.out.println("请求成功,返回参数:" + result.getTradeStatus() +"  " + result.getUserName());
            } else {
                isSuccess = false;
                error = "请求失败,返回结果:" + res.getRespCode() + "," + res.getRespMsg();
            }
        }
        catch (Exception ex) {
            isSuccess = false;
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            ex.printStackTrace(pw);
            error = sw.toString();
        }

        //保存http日志
        logService.saveHttpLog(isSuccess,config.getChargeType(),"家庭医生签约支付查询","POST",null,msgBody,response,error,logService.onepayType);

        if(!isSuccess)
        {
            throw new Exception(error);
        }

        return result;
    }

    /**
     * 生成电子社保卡
     */
    public String createSicard(String patient,String openid) throws Exception
    {
        Boolean isSuccess = true;
        String msgBody = "";
        String response = "";
        String error = "";
        String result = "";

        String appId = config.getOnepayAppId();
        String appSecret = config.getOnepayAppSecret();
        OnepayDefaultClient onepayClient = new OnepayDefaultClient(config.getOnepayApi(),appId, appSecret, signType, encryptType);

        try {
            RequestParams requestParams = new RequestParams();
            requestParams.setAppId(appId);
            requestParams.setTimestamp(DateUtil.getCurrentDateTime());
            requestParams.setSignType(signType);
            requestParams.setEncryptType(encryptType);
            requestParams.setTimestamp(DateUtil.getCurrentDateTime());

            // 请求报文体参数，详见接口文档各接口——请求参数定义
            // 如医保绑卡信息请求参数
            JSONObject params = new JSONObject();
            params.put("openId", openid);
            params.put("accId", SystemConf.getInstance().getAppId());  //微信公众号开发者ID
            requestParams.setParam(params);
            requestParams.setTransType(config.getCreateSicardType());

            msgBody =  JSON.toJSONString(requestParams);
            ResponseParams<JSONObject> res = onepayClient.execute(requestParams);
            response =  JSON.toJSONString(res);

            // 如医保卡绑卡信息返回参数
            if (OnepayDefaultClient.isSuccessful(res)) {
                JSONObject json = res.getParam();
                result = String.valueOf(json.get("sicardUrl"));      //电子社保卡连接

                //保存到患者表
            }
            else {
                isSuccess = false;
                error = "请求失败,返回结果:" + res.getRespCode() + "," + res.getRespMsg();
            }
        }
        catch (Exception ex) {
            isSuccess = false;
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            ex.printStackTrace(pw);
            error = sw.toString();
        }

        //保存http日志
        logService.saveHttpLog(isSuccess,config.getBindCardType(),"生成电子社保卡","POST",null,msgBody,response,error,logService.onepayType);

        if(!isSuccess)
        {
            throw new Exception(error);
        }

        return result;
    }


    /**
     *更新所有记录的交易状态
     */
    private List<WlyyCharge> updateTradeStatus(List<WlyyCharge> list)
    {
        //更新交易状态
        if(list!=null &&list.size()>0)
        {
            for(WlyyCharge item:list)
            {
                try{
                    Charge charge = chargeQuery(item.getCode());
                    if(charge!=null)
                    {
                        item.setTradeStatus(charge.getTradeStatus());            //  交易状态0 成功 1 失败 2 已退款
                        item.setChargeNo(charge.getChargeNo());       //  流水号
                        item.setChargeTime(charge.getChargeTime());      // 扣费时间
                        item.setMedOrgNo(charge.getMedOrgNo()); // 医疗机构编码
                        item.setMedOrgName(charge.getMedOrgName());  //医疗机构名称
                        item.setBillNo(charge.getBillNo());  //待结算费用单据号
                    }

                }
                catch (Exception ex)
                {
                    System.out.print("update trade status fail!");
                }
            }

            chargeDao.save(list);
        }

        return list;
    }

    /**
     * 通过交易关联代码获取交易列表
     */
    public List<WlyyCharge> chargeList(String chargeType,String chargeRelation) throws Exception
    {
        List<WlyyCharge> list = chargeDao.findByChargeTypeAndChargeRelation(chargeType,chargeRelation);

        return updateTradeStatus(list);
    }

    /**
     * 通过患者代码获取交易列表
     */
    public List<WlyyCharge> chargeListByPatient(String patient, Integer page, Integer size) throws Exception
    {

        PageRequest pageRequest = new PageRequest(page - 1, size);
        List<WlyyCharge> list = chargeDao.findByPatient(patient,pageRequest);

        return updateTradeStatus(list);
    }
}
