package com.kmall.api.api.pingan;

import com.kmall.api.annotation.IgnoreAuth;
import com.kmall.api.annotation.LoginUser;
import com.kmall.api.entity.OrderProcessRecordEntity;
import com.kmall.api.entity.OrderVo;
import com.kmall.api.entity.UserVo;
import com.kmall.api.entity.cus.pay.data.open.CusPayDataOpenVo;
import com.kmall.api.service.*;
import com.kmall.api.service.cus.pay.data.open.ApiCusPayDataOpenService;
import com.kmall.manager.manager.pay.wxpay.WxPayPropertiesBuilder;
import com.kmall.api.service.pingan.ApiPinganPayOrderService;
import com.kmall.api.service.pingan.ApiPinganResponseService;
import com.kmall.api.util.ApiBaseAction;
import com.kmall.api.util.CommonUtil;
import com.kmall.common.constant.Dict;
import com.kmall.common.utils.Constant;
import com.kmall.common.utils.MapUtils;
import com.kmall.common.utils.StringUtils;
import com.kmall.manager.manager.pingan.PinganUtil;
import com.kmall.manager.manager.pingan.dto.PinganPayOrderDto;
import com.kmall.manager.manager.pingan.dto.PinganResponseDto;
import com.kmall.manager.manager.pingan.properties.PinganPayPropertiesBuilder;
import com.kmall.manager.manager.pingan.utils.InterfaceParams;
import com.kmall.manager.manager.pingan.utils.TLinx2Util;
import com.kmall.manager.manager.pingan.utils.TLinxAESCoder;
import net.sf.json.JSONObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.math.BigDecimal;
import java.util.*;

@RestController
@RequestMapping("api/pay/pingan")
public class ApiPayPinganController extends ApiBaseAction {

    private Log logger = LogFactory.getLog(ApiPayPinganController.class);

    private static final String SUCCESS_CODE = "0";

    @Autowired
    private ApiOrderService orderService;

    @Autowired
    private ApiPayService payService;

    @Autowired
    private ApiPinganResponseService pinganResponseService;

    @Autowired
    private ApiPinganPayOrderService pinganPayOrderService;

    @Autowired
    private ApiOrderProcessRecordService orderProcessRecordService;

    @Autowired
    private ApiUserService userService;

    @Autowired
    private ApiCusPayDataOpenService cusPayDataOpenService;

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


    /**
     * 平安下单接口
     * @return
     */
    @GetMapping("payorder")
    public Object payorder(@LoginUser UserVo loginUser, Long[] orderIds,String isMergePay) {
        loginUser = userService.queryObject(loginUser.getId());

        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();

            //如此次是单笔支付，则判断下单时该商户订单是否是拆单订单，如果都满足，则更新商户订单号，生成新的预支付信息
            if(Dict.isMergePay.item_0.getItem().equalsIgnoreCase(isMergePay)) {
                if ("2".equalsIgnoreCase(orderInfo.getIsMergePay())) {//多笔订单单笔支付,则商户订单号，生成新的预支付信息
//                    merchOrderSn = "EMATO" + new SimpleDateFormat("yyyyMMddhhmmss").format(new Date());
                    merchOrderSn = "EMATO"+ CommonUtil.generateOrderNumber();
                    orderInfo.setMerchOrderSn(merchOrderSn);
                } else {
                    // 取消订单
                   /*PinganResponseDto payCancel = PinganUtil.pinganPayCancel(null, orderInfo.getMerchOrderSn());
                    if (payCancel == null) {
                        logger.info("平安取消订单接口调用失败！");
                        return toResponsFail("下单失败");
                    }
                    payCancel.setOutNo(orderInfo.getMerchOrderSn());
                    payCancel.setCreateTime(new Date());
                    pinganResponseService.save(payCancel);
                    if (!SUCCESS_CODE.equals(payCancel.getErrcode()) && !"8002".equals(payCancel.getErrcode())) {
                        return toResponsFail(payCancel.getMsg());
                    }*/

                    merchOrderSn = "EMATO"+ CommonUtil.generateOrderNumber();
                    orderInfo.setMerchOrderSn(merchOrderSn);
                }
            }

            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().toString()));
                entity.setPayStartTime(new Date());
                entity.setId(processRecordEntity.getId());
                processRecordEntityList.add(entity);
            }
            actual_price = actual_price.add(orderInfo.getActual_price());
        }

        try {
            String timestamp = new Date().getTime() / 1000 + "";    // 时间

            // 固定参数
            TreeMap<String, String> postmap = new TreeMap<String, String>();    // 请求参数的map

            postmap.put("open_id", PinganPayPropertiesBuilder.instance().getPayOpenId());
            postmap.put("timestamp", timestamp);

            TreeMap<String, String> param = new TreeMap<>();
            param.put("out_no", merchOrderSn);
            param.put("pmt_tag", "WeixinOL");
            param.put("original_amount", actual_price.multiply(Constant.ONE_HUNDRED).intValue()+"");//分为单位
            param.put("trade_amount", actual_price.multiply(Constant.ONE_HUNDRED).intValue()+"");//分为单位
            param.put("sub_appid", WxPayPropertiesBuilder.instance().getAppId());
            param.put("sub_openid", loginUser.getWeixin_openid());
            param.put("trade_type", "JSAPI");
            // 实名认证
            param.put("user_creid", loginUser.getIdNo());
            param.put("user_truename", loginUser.getUsername());

            param.put("notify_url", PinganPayPropertiesBuilder.instance().getNotifyUrl());

            //数据加密，加签
            TLinx2Util.handleEncrypt(param, postmap);
            TLinx2Util.handleSign(postmap);

            //请求
            String rspStr = TLinx2Util.handlePost(postmap, InterfaceParams.PAYORDER);
            System.out.println("返回字符串=" + rspStr);

            //解析数据,处理数据
            return analysisResponse(rspStr, merchOrderSn, orderVoList);

        } catch (Exception e) {
            e.printStackTrace();
//            updateFailProcessBatch(processRecordEntityList, "下单失败,error=" + e.getMessage());//更新订单流转信息
            return toResponsFail("下单失败,error=" + e.getMessage());
        }
    }


    /**
     * 更新订单支付失败流转信息
     * @param processRecordEntityList
     * @param return_msg
     */
    private 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 rspStr
     * @return
     */
    private Object analysisResponse(String rspStr, String merchOrderSn, List<OrderVo> orderVoList) throws Exception {
        JSONObject respObject = JSONObject.fromObject(rspStr);
        logger.info("返回错误码：【" + MapUtils.getString("errcode", respObject) + "】");
        logger.info("返回错误提示【" + MapUtils.getString("msg", respObject) + "】");
        logger.info("平安支付下单返回数据:【" + MapUtils.getString("data", respObject) + "】");
        logger.info("接口签名【" + MapUtils.getString("sign", respObject) + "】");

        if (!respObject.isEmpty()) {
            PinganResponseDto response = new PinganResponseDto();
            response.setErrcode(MapUtils.getString("errcode", respObject));
            response.setMsg(MapUtils.getString("msg", respObject));
            response.setData(MapUtils.getString("data", respObject));
            response.setSign(MapUtils.getString("sign", respObject));
            if (StringUtils.isNotEmpty(MapUtils.getString("timestamp", respObject))) {
                Long timestamp = Long.parseLong(MapUtils.getString("timestamp", respObject)) * 1000;
                response.setTimestamp(new Date(timestamp));
            }
            response.setReqInterface(InterfaceParams.PAYORDER);
            response.setCreateTime(new Date());
            response.setOutNo(merchOrderSn);

            if (SUCCESS_CODE.equals(response.getErrcode())) {
                // 验签, 判断是否下单成功
                if (TLinx2Util.verifySign(respObject)) {
                    String dataJson = TLinxAESCoder.decrypt(response.getData(), PinganPayPropertiesBuilder.instance().getPayOpenKey());

                    // 添加平安支付回执
                    response.setDatajson(dataJson);
                    pinganResponseService.save(response);

                    // 参数解密，添加平安支付订单信息
                    if (dataJson != null) {
                        JSONObject dataObject = JSONObject.fromObject(dataJson);
                        PinganPayOrderDto payorder = PinganUtil.buildPayOrderDto(dataObject);
                        payorder.setCreateTime(new Date());
                        pinganPayOrderService.save(payorder);

                        String prepay_id = payorder.getTradeNo();
                        for (OrderVo orderInfo : orderVoList) {
                            orderInfo.setPay_id(prepay_id);
                            orderInfo.setPay_status(Integer.parseInt(Dict.payStatus.item_1.getItem())); // 付款中
                            orderInfo.setOrder_status(Integer.parseInt(Dict.orderStatus.item_100.getItem()));
                            orderInfo.setPayFlag(Dict.payFlag.item_pingan.getItem());

                            if(!orderInfo.getOrderBizType().equalsIgnoreCase(Dict.orderBizType.item_11.getItem())) {
                                CusPayDataOpenVo cusPayDataOpen = cusPayDataOpenService.queryObjectByOrderNo(orderInfo.getOrder_sn());
                                if (cusPayDataOpen == null) {
                                    cusPayDataOpen = new CusPayDataOpenVo();
                                    cusPayDataOpen.setMerchOrderSn(merchOrderSn);
                                    cusPayDataOpen.setOrderNo(orderInfo.getOrder_sn());
                                    cusPayDataOpen.setInitalRequest(rspStr);
                                    cusPayDataOpen.setCreateTime(new Date());
                                    cusPayDataOpen.setModTime(new Date());
                                    cusPayDataOpenService.save(cusPayDataOpen);
                                } else {
                                    cusPayDataOpen.setMerchOrderSn(merchOrderSn);
                                    cusPayDataOpen.setInitalRequest(rspStr);
                                    cusPayDataOpen.setModTime(new Date());
                                    cusPayDataOpenService.update(cusPayDataOpen);
                                }
                            }
                        }
                        orderService.updateBatch(orderVoList);

                        Map<String, Object> payParam = new HashMap<>();
                        payParam.put("timeStamp", MapUtils.getString("timeStamp", dataObject));
                        payParam.put("nonceStr", MapUtils.getString("nonceStr", dataObject));
                        payParam.put("signType", MapUtils.getString("signType", dataObject));
                        payParam.put("package", MapUtils.getString("package", dataObject));
                        payParam.put("paySign", MapUtils.getString("paySign", dataObject));
                        return toResponsSuccess(payParam);
                    }
                }
            } else if ("8045".equals(response.getErrcode())) {
                PinganPayOrderDto payOrderDto = pinganPayOrderService.queryByOutNo(merchOrderSn);
                if (payOrderDto != null) {
                    Map<String, Object> payParam = new HashMap<>();
                    payParam.put("timeStamp", payOrderDto.getTimeStamp());
                    payParam.put("nonceStr", payOrderDto.getNoncestr());
                    payParam.put("signType", payOrderDto.getSigntype());
                    payParam.put("package", payOrderDto.getPrepayId());
                    payParam.put("paySign", payOrderDto.getPaysign());
                    return toResponsSuccess(payParam);
                }

                pinganResponseService.save(response);
                logger.debug("下单失败！" + response.getMsg());
                return toResponsFail("下单失败！");
            } else {
                pinganResponseService.save(response);
                logger.debug("下单失败！" + response.getMsg());
                return toResponsFail("下单失败！");
            }
        }

        return toResponsFail("下单失败！");
    }


    /**
     * 平安订单回调接口
     *
     * @return
     */
    @IgnoreAuth
    @RequestMapping(value = "/notify", method = RequestMethod.POST)
    @ResponseBody
    public String notify(HttpServletRequest request, HttpServletResponse response) {
        logger.info("平安订单回调接口>>>>>>pingan notify start");
        String openId = request.getParameter("open_id");
        if (StringUtils.isNotEmpty(openId) && openId.equals(PinganPayPropertiesBuilder.instance().getPayOpenId())) {
            String ordNo = request.getParameter("ord_no");
            String timestamp = request.getParameter("timestamp");
            String randStr = request.getParameter("rand_str");
            String outNo = request.getParameter("out_no");
            String status = request.getParameter("status");
            String tradeResult = request.getParameter("trade_result");
            String payTime = request.getParameter("pay_time");
            String sign = request.getParameter("sign");

            Map<String, Object> params = new TreeMap<>();
            params.put("open_id", openId);
            params.put("ord_no", ordNo);
            params.put("timestamp", timestamp);
            params.put("rand_str", randStr);
            params.put("out_no", outNo);
            params.put("status", status);
            params.put("trade_result", tradeResult);
            params.put("pay_time", payTime);
            params.put("sign", sign);

            PinganResponseDto responseDto = new PinganResponseDto();
            responseDto.setOutNo(outNo);
            responseDto.setReqInterface(InterfaceParams.NOTIFY);
            responseDto.setDatajson(JSONObject.fromObject(params).toString());
            responseDto.setCreateTime(new Date());
            pinganResponseService.save(responseDto);

            JSONObject result = JSONObject.fromObject(tradeResult);
            payService.notify(result.getString("out_trade_no"), result.getString("total_fee"), result.getString("transaction_id"), result.getString("time_end"), JSONObject.fromObject(params).toString());
            return "notify_success";
        } else {
            logger.info("平安订单回调接口openId不匹配");
        }
        logger.info("平安订单回调接口>>>>>>pingan notify end");
        return "notify_fail";
    }

}
