package com.kmall.api.api;

import com.kmall.api.annotation.IgnoreAuth;
import com.kmall.api.annotation.LoginUser;
import com.kmall.api.contants.Dict;
import com.kmall.api.dao.ApiOrderRefundMapper;
import com.kmall.api.entity.*;
import com.kmall.api.service.*;
import com.kmall.api.service.pay.wxpay.WxPayPropertiesBuilder;
import com.kmall.api.util.ApiBaseAction;
import com.kmall.common.utils.CharUtil;
import com.kmall.common.utils.Constant;
import com.kmall.common.utils.MapUtils;
import com.kmall.common.utils.XmlUtil;
import com.kmall.common.utils.wechat.AESUtil;
import com.kmall.common.utils.wechat.WechatRefundApiResult;
import com.kmall.common.utils.wechat.WechatRefundResult;
import com.kmall.common.utils.wechat.WechatUtil;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 作者: @author Scott <br>
 * 时间: 2017-08-11 08:32<br>
 * 描述: ApiIndexController <br>
 */
@RestController
@RequestMapping("/api/pay")
public class ApiPayController extends ApiBaseAction {
    private Logger logger = Logger.getLogger(ApiPayController.class);
    @Autowired
    private ApiOrderService orderService;
    @Autowired
    private ApiOrderGoodsService orderGoodsService;
    @Autowired
    private ApiPayService apiPayService;
    @Autowired
    private ApiOrderProcessRecordService orderProcessRecordService;
    @Autowired
    private ApiOrderExceptionRecordService apiOrderExceptionRecordService;

    @Autowired
    private ApiOrderRefundMapper mallOrderRefundMapper;



    /**
     */
    @RequestMapping("index")
    public Object index(@LoginUser UserVo loginUser) {
        return toResponsSuccess("");
    }

    /**
     * 获取支付的请求参数
     */
    @GetMapping("pay_prepay")
    public Object payPrepay(@LoginUser UserVo loginUser, Long[] orderIds,String isMergePay) {
        List<Long> orderIdList=new ArrayList<>();
        String merchOrderSn = "";
        for(int i=0;i<orderIds.length;i++){
            orderIdList.add(orderIds[i]);
        }
        BigDecimal actual_price = Constant.ZERO;
        List<OrderVo> orderVoList = orderService.queryObjectByIdList(orderIdList);
        List<OrderProcessRecordEntity> processRecordEntityList = new ArrayList<>();

        for (OrderVo orderInfo:orderVoList) {
            if (orderInfo.getOrder_status() == 101) {
                return toResponsObject(400, "订单号为"+orderInfo.getOrder_sn()+"的订单超时支付，已取消", "");
            }
            if (orderInfo.getPay_status() != 0 && orderInfo.getPay_status() != 1) {
                return toResponsObject(400, "订单号为"+orderInfo.getOrder_sn()+"的订单已支付，请不要重复操作", "");
            }
            merchOrderSn = orderInfo.getMerchOrderSn();
            OrderVo orderVo = new OrderVo();
            if(Dict.isMergePay.item_0.getItem().equalsIgnoreCase(isMergePay)){//如此次是单笔支付，则查询下单时该商户订单是否是拆单订单，如果都满足，则更新商户订单号，生成新的预支付信息
                if(orderService.queryCountByMerchOrderSn(merchOrderSn) > 1) {//不止一笔订单则为拆单订单
                    merchOrderSn = "EMATO" + new SimpleDateFormat("yyyyMMddhhmmss").format(new Date());
                    orderInfo.setMerchOrderSn(merchOrderSn);
                    orderVo.setMerchOrderSn(orderInfo.getMerchOrderSn());
                }
            }
            orderVo.setIsMergePay(isMergePay);
            orderVo.setId(orderInfo.getId());
            orderService.update(orderVo);

            OrderProcessRecordEntity processRecordEntity = orderProcessRecordService.queryObjectByOrderSn(orderInfo.getOrder_sn());
            if(processRecordEntity != null){
                OrderProcessRecordEntity entity = new OrderProcessRecordEntity();
                entity.setOrderSn(orderInfo.getOrder_sn());
                entity.setUserId(Integer.valueOf(loginUser.getId()+""));
                entity.setPayStartTime(new Date());
                entity.setId(processRecordEntity.getId());
                processRecordEntityList.add(entity);
            }
            actual_price = actual_price.add(orderInfo.getActual_price());

        }

        String nonceStr = CharUtil.getRandomString(32);

        //https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3
        Map<Object, Object> resultObj = new HashMap();

        try {
            Map<Object, Object> parame = new TreeMap<>();
            //parame.put("appid", ResourceUtil.getConfigByName("wx.appId"));
            parame.put("appid", WxPayPropertiesBuilder.instance().getAppId());
            //parame.put("mch_id", ResourceUtil.getConfigByName("wx.mchId"));// 商家账号。
            parame.put("mch_id", WxPayPropertiesBuilder.instance().getMchId());// 商家账号。
            String randomStr = CharUtil.getRandomNum(18).toUpperCase();
            parame.put("nonce_str", randomStr);// 随机字符串
            parame.put("out_trade_no", merchOrderSn);// 商户订单编号
            parame.put("body", "商城-支付");// 商品描述

            //订单的商品
            List<OrderGoodsVo> orderGoods = orderGoodsService.queryListByIds(orderIdList);
            if (null != orderGoods) {
                String body = "商城-";
                for (OrderGoodsVo goodsVo : orderGoods) {
                    body = body + goodsVo.getGoods_name() + "、";
                }
                if (body.length() > 0) {
                    body = body.substring(0, body.length() - 1);
                }
                parame.put("body", body);// 商品描述
            }
            //支付金额
//            parame.put("total_fee", orderInfo.getActual_price().multiply(Constant.ONE_HUNDRED).intValue()));//todo 消费金额
            parame.put("total_fee", actual_price.multiply(Constant.ONE_HUNDRED).intValue());// 消费金额
            //parame.put("notify_url", ResourceUtil.getConfigByName("wx.notifyUrl"));// 回调地址
            parame.put("notify_url", WxPayPropertiesBuilder.instance().getNotifyUrl());// 回调地址
            //parame.put("trade_type", ResourceUtil.getConfigByName("wx.tradeType"));// 交易类型APP
            parame.put("trade_type", WxPayPropertiesBuilder.instance().getTradeType());// 交易类型APP
//            parame.put("spbill_create_ip", getClientIp());
            //parame.put("spbill_create_ip", ResourceUtil.getConfigByName("spbillCreateIp"));
            parame.put("spbill_create_ip", WxPayPropertiesBuilder.instance().getSpbillCreateIp());
            parame.put("openid", loginUser.getWeixin_openid());
//            parame.put("sign_type", "MD5");
            //String sign = WechatUtil.arraySign(parame, ResourceUtil.getConfigByName("wx.paySignKey"));
            String sign = WechatUtil.arraySign(parame, WxPayPropertiesBuilder.instance().getPaySignKey());
            parame.put("sign", sign);// 数字签证

            String xml = MapUtils.convertMap2Xml(parame);
            logger.info("xml:" + xml);
            //Map<String, Object> resultUn = XmlUtil.xmlStrToMap(WechatUtil.requestOnce(ResourceUtil.getConfigByName("wx.uniformorder"), xml));
            Map<String, Object> resultUn = XmlUtil.xmlStrToMap(WechatUtil.requestOnce(WxPayPropertiesBuilder.instance().getUniformorder(), xml));
            // 响应报文
            String return_code = MapUtils.getString("return_code", resultUn);
            String return_msg = MapUtils.getString("return_msg", resultUn);
            //
            if (return_code.equalsIgnoreCase("FAIL")) {
                updateFailProcessBatch(processRecordEntityList, "支付失败," +return_msg);//更新订单流转信息
                addOrderExceptionRecord(orderVoList, Dict.exceptionStatus.item_00.getItem(),"支付失败," +return_msg);//记录订单异常信息
                return toResponsFail("支付失败," + return_msg);
            } else if (return_code.equalsIgnoreCase("SUCCESS")) {
                // 返回数据
                String result_code = MapUtils.getString("result_code", resultUn);
                String err_code_des = MapUtils.getString("err_code_des", resultUn);
                if (result_code.equalsIgnoreCase("FAIL")) {
                    updateFailProcessBatch(processRecordEntityList, "支付失败," +err_code_des);//更新订单流转信息
                    addOrderExceptionRecord(orderVoList, Dict.exceptionStatus.item_00.getItem(),"支付失败," +err_code_des);//记录订单异常信息
                    return toResponsFail("支付失败," + err_code_des);
                } else if (result_code.equalsIgnoreCase("SUCCESS")) {
                    apiPayService.payPrepay(resultObj, resultUn, nonceStr, orderVoList);
                    orderProcessRecordService.updateBatch(processRecordEntityList);//更新订单流转信息
                    return toResponsObject(0, "微信统一订单下单成功", resultObj);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            updateFailProcessBatch(processRecordEntityList, "下单失败,error=" + e.getMessage());//更新订单流转信息
            return toResponsFail("下单失败,error=" + e.getMessage());
        }
        return toResponsFail("下单失败");
    }

    /**
     * 更新订单支付失败流转信息
     * @param processRecordEntityList
     * @param return_msg
     */
    public void updateFailProcessBatch(List<OrderProcessRecordEntity> processRecordEntityList,String return_msg){
        for (OrderProcessRecordEntity orderProcessRecordEntity : processRecordEntityList) {
            orderProcessRecordEntity.setIsPaymentSend(Dict.isSend.item_0.getItem());
            orderProcessRecordEntity.setProcessContent(return_msg);
        }
        orderProcessRecordService.updateBatch(processRecordEntityList);
    }

    /**
     * 记录订单异常信息
     * @param orderVoList
     * @param exceptionStatus
     * @param expContent
     */
    public void addOrderExceptionRecord(List<OrderVo> orderVoList,String exceptionStatus,String expContent){
        for (OrderVo orderInfo: orderVoList) {
            MallOrderExceptionRecord mallOrderExceptionRecord = new MallOrderExceptionRecord();
            mallOrderExceptionRecord.setUserId(Integer.parseInt(orderInfo.getUser_id()+""));
            mallOrderExceptionRecord.setOrderSn(orderInfo.getOrder_sn());
            mallOrderExceptionRecord.setExceptionStatus(exceptionStatus);
            mallOrderExceptionRecord.setExceptionContent(expContent);
            mallOrderExceptionRecord.setCreateTime(new Date());
            apiOrderExceptionRecordService.save(mallOrderExceptionRecord);
        }
    }

    /**
     * 微信订单回调接口
     *
     * @return
     */
    @IgnoreAuth
    @RequestMapping(value = "/notify", produces = "text/html;charset=UTF-8")
    @ResponseBody
    public void notify(HttpServletRequest request, HttpServletResponse response) {
        logger.error("notify start");
        try {
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");
            response.setHeader("Access-Control-Allow-Origin", "*");
            InputStream in = request.getInputStream();
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            out.close();
            in.close();
            String reponseXml = new String(out.toByteArray(), "utf-8");//xml数据
            logger.error("reponseXml:" + reponseXml);
            WechatRefundApiResult result = (WechatRefundApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatRefundApiResult.class);
            String result_code = result.getResult_code();
            if (result_code.equalsIgnoreCase("FAIL")) {
                String out_trade_no = result.getOut_trade_no();//订单编号
                logger.error("订单" + out_trade_no + "支付失败");
                response.getWriter().write(setXml("SUCCESS", "OK"));
                response.getWriter().close();
            } else if (result_code.equalsIgnoreCase("SUCCESS")) {
                //验签
                String sign = result.getSign();
                String time_end = result.getTime_end();
                String out_trade_no = result.getOut_trade_no();//商户订单号
                String transaction_id = result.getTransaction_id();//微信支付订单号
                String total_fee = result.getTotal_fee();//订单编号
                logger.error("订单" + out_trade_no + "支付成功");
                // 业务处理
                apiPayService.notify(out_trade_no,total_fee,transaction_id,time_end);
                response.getWriter().write(setXml("SUCCESS", "OK"));
            }
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
    }

    /**
     * 订单退款请求 todo 小程序用户暂不给退款
     */
    /*@GetMapping("refund")
    public Object refund(@LoginUser UserVo loginUser, Long orderId) {
        //
        OrderVo orderInfo = orderService.queryObject(orderId);

        if (null == orderInfo) {
            return toResponsObject(400, "订单已取消", "");
        }

        if (orderInfo.getOrder_status() == 401 || orderInfo.getOrder_status() == 402) {
            return toResponsObject(400, "订单已退款", "");
        }

        if (orderInfo.getPay_status() != 2) {
            return toResponsObject(400, "订单未付款，不能退款", "");
        }

//        WechatRefundApiResult result = WechatUtil.wxRefund(orderInfo.getId().toString(),
//                orderInfo.getActual_price().doubleValue(), orderInfo.getActual_price().doubleValue());
        WechatRefundApiResult result = WechatUtil.wxRefund(orderInfo.getMerchOrderSn().toString(),
                orderInfo.getActual_price().doubleValue(), orderInfo.getActual_price().doubleValue());
        if (result.getResult_code().equals("SUCCESS")) {
            apiPayService.refund(orderInfo,result,"");
            return toResponsObject(400, "成功退款", "");
        } else {
            MallOrderRefund mallOrderRefund = mallOrderRefundMapper.queryObjectByOrderId(orderInfo.getId()+"");
            MallOrderRefund orderRefund = new MallOrderRefund();
            orderRefund.setRefundType(Integer.parseInt(Dict.RefundType.item_1.getItem()));
            orderRefund.setRefundMoney(BigDecimal.valueOf(orderInfo.getActual_price().multiply(Constant.ONE_HUNDRED).doubleValue()));
            orderRefund.setRefundStatus(Integer.parseInt(Dict.RefundStatus.item_3.getItem()));
            orderRefund.setModTime(new Date());
            if(mallOrderRefund !=null){
                orderRefund.setId(mallOrderRefund.getId());
                mallOrderRefundMapper.update(orderRefund);
            }

            MallOrderExceptionRecord mallOrderExceptionRecord = new MallOrderExceptionRecord();
            mallOrderExceptionRecord.setUserId(Integer.parseInt(orderInfo.getUser_id()+""));
            mallOrderExceptionRecord.setOrderSn(orderInfo.getOrder_sn());
            mallOrderExceptionRecord.setExceptionStatus(Dict.exceptionStatus.item_03.getItem());
            mallOrderExceptionRecord.setExceptionContent("退款失败"+result.getErr_code_des());
            mallOrderExceptionRecord.setCreateTime(new Date());
            apiOrderExceptionRecordService.save(mallOrderExceptionRecord);

            return toResponsObject(400, "退款失败"+result.getErr_code_des(), "");
        }
    }*/


    /**
     * 微信订单退款回调接口
     *
     * @return
     */
    @IgnoreAuth
    @RequestMapping(value = "/refundNotify", produces = "text/html;charset=UTF-8")
    @ResponseBody
    public void refundNotify(HttpServletRequest request, HttpServletResponse response) {
        logger.error("refundNotify start");
        try {
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");
            response.setHeader("Access-Control-Allow-Origin", "*");
            InputStream in = request.getInputStream();
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            out.close();
            in.close();
            String reponseXml = new String(out.toByteArray(), "utf-8");//xml数据
            logger.error("reponseXml:" + reponseXml);
            WechatRefundResult result = (WechatRefundResult) XmlUtil.xmlStrToBean(reponseXml, WechatRefundResult.class);

            if (result.getReturn_code().equalsIgnoreCase("FAIL")) {
                logger.info("微信查询接口调用失败： "+result.getReturn_msg());
                response.getWriter().write(setXml("SUCCESS", "OK"));
                response.getWriter().close();
            }else {
                String req_info = result.getReq_info();//加密信息
                String aesResult = AESUtil.decryptData(req_info);
                System.out.println(aesResult);
                WechatRefundApiResult refundApiResult = (WechatRefundApiResult) XmlUtil.xmlStrToBean(aesResult, WechatRefundApiResult.class);

                logger.error("订单" + refundApiResult.getOut_trade_no() + "退款成功");
                // 业务处理
                apiPayService.refundNotify(refundApiResult);
                response.getWriter().write(setXml("SUCCESS", "OK"));
            }

        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
    }



    /**
     * 订单退款请求
     */
    @IgnoreAuth
    @GetMapping("test")
    public Object test(Long orderId) {
        OrderVo orderInfo = orderService.queryObject(orderId);
        // 微信通知
        orderService.notifyPaySuccess(orderInfo);
        return null;
    }

    //返回微信服务
    public static String setXml(String return_code, String return_msg) {
        return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";
    }

    //模拟微信回调接口
    public static String callbakcXml(String orderNum) {
        return "<xml><appid><![CDATA[wx2421b1c4370ec43b]]></appid><attach><![CDATA[支付测试]]></attach><bank_type><![CDATA[CFT]]></bank_type><fee_type><![CDATA[CNY]]></fee_type> <is_subscribe><![CDATA[Y]]></is_subscribe><mch_id><![CDATA[10000100]]></mch_id><nonce_str><![CDATA[5d2b6c2a8db53831f7eda20af46e531c]]></nonce_str><openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid> <out_trade_no><![CDATA[" + orderNum + "]]></out_trade_no>  <result_code><![CDATA[SUCCESS]]></result_code> <return_code><![CDATA[SUCCESS]]></return_code><sign><![CDATA[B552ED6B279343CB493C5DD0D78AB241]]></sign><sub_mch_id><![CDATA[10000100]]></sub_mch_id> <time_end><![CDATA[20140903131540]]></time_end><total_fee>1</total_fee><trade_type><![CDATA[JSAPI]]></trade_type><transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id></xml>";
    }
}