package com.iformall.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.iformall.common.ErrorCode;
import com.iformall.common.Result;
import com.iformall.common.ResultData;
import com.iformall.domain.po.PosOrder;
import com.iformall.domain.po.PosPayOrder;
import com.iformall.domain.po.WxMerchantBUser;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.pay.WxPayConstant;
import com.iformall.pay.WxPayment;
import com.iformall.utils.PosUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class PosBrunService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private String posDevId;

    @Autowired
    private String posReqKey;

    @Autowired
    private String posResKey;

    @Autowired
    private String posUrl;

    @Autowired
    private PosOrderService posOrderService;

    @Autowired
    private PosPayOrderService posPayOrderService;

    PosUtil posUtil = new PosUtil();

    /**
     * 检查POS Server是否正常
     * @return
     */
    public ResultData checkAvaiable() {
        try {
            String resStr = posUtil.checkPosMemServer(posUrl);
            if (resStr != null) {
                return new ResultData();
            } else {
                return new ResultData(Result.ERROR, "无返回值");
            }
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }
    }

    /**
     * 商户POS用户/B端用户登录检查
     * @param user
     * @param phone
     * @param password
     * @return
     */
    public ResultData checkUserPassword(WxMerchantBUser user, String phone, String password) {
        try {
            String resStr = posUtil.checkUserPassword(posUrl, posDevId, posReqKey,
                    user.getTenantId(), phone, password);
            if (resStr != null) {
                JSONObject retObj = JSON.parseObject(resStr);
                Map options = retObj;
                if (!WxPayment.verifyNotifyHMAC(options, posResKey)) {
                    return new ResultData(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR);
                } else {
                    return new ResultData(resStr);
                }
            } else {
                return new ResultData(Result.ERROR, "无返回值");
            }
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }
    }

    /**
     * 获取会员折扣/优惠券/消费卡是否启用
     * @param tenantId
     * @return
     */
    public ResultData getPosMemConfig(String tenantId) {
        try {
            String resStr = posUtil.getPosMemConfig(posUrl, posDevId, posReqKey, tenantId);
            if (resStr != null) {
                JSONObject retObj = JSON.parseObject(resStr);
                Map options = retObj;
                if (!WxPayment.verifyNotifyHMAC(options, posResKey)) {
                    return new ResultData(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR);
                } else {
                    return new ResultData(resStr);
                }
            } else {
                return new ResultData(Result.ERROR, "无返回值");
            }
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }
    }

    /**
     * 获取注册二维码及小票二维码规则
     * @param tenantId
     * @return
     */
    public ResultData getQrCode(String tenantId) {
        try {
            String resStr = posUtil.getQrCode(posUrl, posDevId, posReqKey, tenantId);
            if (resStr != null) {
                JSONObject retObj = JSON.parseObject(resStr);
                Map options = retObj;
                if (!WxPayment.verifyNotifyHMAC(options, posResKey)) {
                    return new ResultData(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR);
                } else {
                    return new ResultData(resStr);
                }
            } else {
                return new ResultData(Result.ERROR, "无返回值");
            }
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }
    }

    /**
     * 会员识别
     * @param user
     * @param memIdStr
     * @param memPhoneStr
     * @param posOrderIdStr
     * @param posAmountStr
     * @return
     */
    public ResultData checkMem(WxMerchantBUser user,
                               String memIdStr, String memPhoneStr,
                               String posOrderIdStr, String posAmountStr) {
        try {
            String resStr = posUtil.checkMem(posUrl, posDevId, posReqKey,
                    user.getTenantId(), String.valueOf(user.getMerchantId()),
                    memIdStr, memPhoneStr, posOrderIdStr, posAmountStr);
            if (resStr != null) {
                JSONObject retObj = JSON.parseObject(resStr);
                Map options = retObj;
                if (!WxPayment.verifyNotifyHMAC(options, posResKey)) {
                    return new ResultData(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR);
                } else {
                    return new ResultData(resStr);
                }
            } else {
                return new ResultData(Result.ERROR, "无返回值");
            }
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }
    }

    /**
     * 券独立核销检查
     * @param user
     * @param verifyType
     * @param couponOrderIdStr
     * @return
     */
    public ResultData checkCouponOrderForIndepentVerify(WxMerchantBUser user,
                                                String verifyType,
                                                String couponOrderIdStr) {
        try {
            String resStr = posUtil.checkCouponOrderForVerify(posUrl, posDevId, posReqKey,
                    user.getTenantId(), String.valueOf(user.getMerchantId()), String.valueOf(user.getId()),
                    verifyType, couponOrderIdStr, null, null);
            if (resStr != null) {
                JSONObject retObj = JSON.parseObject(resStr);
                Map options = retObj;
                if (!WxPayment.verifyNotifyHMAC(options, posResKey)) {
                    return new ResultData(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR);
                } else {
                    return new ResultData(resStr);
                }
            } else {
                return new ResultData(Result.ERROR, "无返回值");
            }
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }
    }

    /**
     * 券交易核销检查
     * @param user
     * @param verifyType
     * @param couponOrderIdStr
     * @param posOrderIdStr
     * @param posAmountStr
     * @return
     */
    public ResultData checkCouponOrderForPayVerify(WxMerchantBUser user,
                                                String verifyType,
                                                String couponOrderIdStr,
                                                String posOrderIdStr, String posAmountStr) {
        try {
            String resStr = posUtil.checkCouponOrderForVerify(posUrl, posDevId, posReqKey,
                    user.getTenantId(), String.valueOf(user.getMerchantId()), String.valueOf(user.getId()),
                    verifyType, couponOrderIdStr, posOrderIdStr, posAmountStr);
            if (resStr != null) {
                JSONObject retObj = JSON.parseObject(resStr);
                Map options = retObj;
                if (!WxPayment.verifyNotifyHMAC(options, posResKey)) {
                    return new ResultData(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR);
                } else {
                    return new ResultData(resStr);
                }
            } else {
                return new ResultData(Result.ERROR, "无返回值");
            }
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }
    }

    /**
     * 券预核销
     * @param user
     * @param couponOrderIdStr
     * @param posOrderIdStr
     * @param posAmountStr
     * @return
     */
    public ResultData couponOrderPreVerify(WxMerchantBUser user,
                                           String couponOrderIdStr, String deductAmountStr,
                                           String posOrderIdStr, String posAmountStr) {
        Integer deductAmount, posAmount;
        Long posOrderId;
        try {
            deductAmount = Integer.valueOf(deductAmountStr);
            posAmount = Integer.valueOf(posAmountStr);
            posOrderId = Long.valueOf(posOrderIdStr);
        } catch (NumberFormatException e) {
            logger.error(ErrorCode.SYS_PARAMETER_CAST_ERROR.getMessage());
            return new ResultData(ErrorCode.SYS_PARAMETER_CAST_ERROR);
        }
        // 1. 创建支付订单
        Date curDate = new Date();
        PosPayOrder posPayOrder = new PosPayOrder();
        posPayOrder.setTenantId(user.getTenantId());
        posPayOrder.setCreateTime(curDate);
        posPayOrder.setUpdateTime(curDate);
        posPayOrder.setOrderId(posOrderId);
        posPayOrder.setBuUserId(user.getId());
        posPayOrder.setType(2);
        posPayOrder.setPayFrom(10);
        posPayOrder.setPayAmount(deductAmount);
        posPayOrder.setPayTimeStart(curDate);
        posPayOrder.setPayTimeEnd(curDate);
        posPayOrder.setPayOrderStatus(EnumPayStatus.PAY_STATUS_WAIT.getCode());
        posPayOrder.setShare(0);
        try {
            posPayOrderService.saveOrUpdate(posPayOrder);
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }

        // 2. POS预核销
        try {
            String resStr = posUtil.couponOrderPreVerify(posUrl, posDevId, posReqKey,
                    user.getTenantId(), String.valueOf(user.getMerchantId()), String.valueOf(user.getId()),
                    couponOrderIdStr, posOrderIdStr, posAmountStr);
            if (resStr != null) {
                JSONObject retObj = JSON.parseObject(resStr);
                Map options = retObj;
                if (!WxPayment.verifyNotifyHMAC(options, posResKey)) {
                    return new ResultData(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR);
                } else {
                    if (retObj.getString(WxPayConstant.RETURN_CODE).equalsIgnoreCase(WxPayConstant.RET_SUCCESS) &&
                            retObj.getString(WxPayConstant.RESULT_CODE).equalsIgnoreCase(WxPayConstant.RET_SUCCESS)) {
                        Integer remainAmount = posAmount;
                        // 获取 返回值
                        JSONArray retArr = retObj.getJSONArray(WxPayConstant.RET);
                        for (int i = 0; i > retArr.size(); i++) {
                            JSONObject couponObj = retArr.getJSONObject(i);
                            if (couponObj == null) {
                                continue;
                            }
                            String deductAmountOfCouponStr = couponObj.getString(WxPayConstant.DEDUCT_AMOUNT);
                            Integer deductAmountofCoupon = Integer.valueOf(deductAmountOfCouponStr);
                            // 新 支付订单状态
                            PosPayOrder updatePayOrder = new PosPayOrder();
                            updatePayOrder.setId(Long.valueOf(couponObj.getLong(WxPayConstant.ID)));
                            updatePayOrder.setPayAmount(deductAmountofCoupon);
                            updatePayOrder.setPayOrderStatus(EnumPayStatus.PAY_STATUS_SUCCESS.getCode());
                            updatePayOrder.setPayTimeEnd(new Date());
                            try {
                                posPayOrderService.saveOrUpdate(updatePayOrder);
                            } catch (MallinkException e) {
                                logger.error(e.getMessage());
                                return new ResultData(e.getErrorCode(), e.getMessage());
                            } catch (Exception e) {
                                logger.error(e.getMessage());
                                return new ResultData(Result.ERROR, e.getMessage());
                            }
                            String remainAmountStr = couponObj.getString(WxPayConstant.REMAIN_AMOUNT);
                            Integer remainAmountofCoupon = Integer.valueOf(remainAmountStr);
                            remainAmount = remainAmountofCoupon;
                        }
                        // 更新 订单状态
                        PosOrder updateOrder = new PosOrder();
                        updateOrder.setId(posOrderId);
                        updateOrder.setRemainAmount(remainAmount);
                        updateOrder.setUpdateDate(new Date());
                        if (remainAmount.equals(0)) {
                            updateOrder.setOrderStatus(EnumPosOrderStatus.PAYMENT_SUCCESS.getCode());
                            retObj.put(WxPayConstant.ORDER_STATUS, EnumPosOrderStatus.PAYMENT_SUCCESS.getCode());
                            retObj.put(WxPayConstant.DEDUCT_AMOUNT, 0);
                        } else {
                            updateOrder.setOrderStatus(EnumPosOrderStatus.PENDING.getCode());
                            retObj.put(WxPayConstant.ORDER_STATUS, EnumPosOrderStatus.PENDING.getCode());
                            retObj.put(WxPayConstant.DEDUCT_AMOUNT, remainAmount);
                        }
                        try {
                            posOrderService.saveOrUpdate(updateOrder);
                        } catch (MallinkException e) {
                            logger.error(e.getMessage());
                            return new ResultData(e.getErrorCode(), e.getMessage());
                        } catch (Exception e) {
                            logger.error(e.getMessage());
                            return new ResultData(Result.ERROR, e.getMessage());
                        }
                        return new ResultData(JSON.toJSONString(retObj));
                    } else {
                        logger.error(resStr);
                        return new ResultData(Result.ERROR, retObj.getString(WxPayConstant.RESULT_DATA));
                    }
                }
            } else {
                return new ResultData(Result.ERROR, "无返回值");
            }
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }
    }

    /**
     * 券预核销取消
     * @param user
     * @param couponOrderIdStr
     * @param posOrderIdStr
     * @param posAmountStr
     * @return
     */
    public ResultData couponOrderPreVerifyCancel(WxMerchantBUser user,
                                                 String couponOrderIdStr,
                                                 String posOrderIdStr, String posAmountStr) {
        try {
            String resStr = posUtil.couponOrderPreVerifyCancel(posUrl, posDevId, posReqKey,
                    user.getTenantId(), String.valueOf(user.getMerchantId()), String.valueOf(user.getId()),
                    couponOrderIdStr, posOrderIdStr, posAmountStr);
            if (resStr != null) {
                JSONObject retObj = JSON.parseObject(resStr);
                Map options = retObj;
                if (!WxPayment.verifyNotifyHMAC(options, posResKey)) {
                    return new ResultData(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR);
                } else {
                    return new ResultData(resStr);
                }
            } else {
                return new ResultData(Result.ERROR, "无返回值");
            }
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }
    }

    /**
     * 券独立核销
     * @param user
     * @param couponOrderIdStr
     * @param posOrderIdStr
     * @return
     */
    public ResultData couponOrderIndependentVerify(WxMerchantBUser user, String couponOrderIdStr, String posOrderIdStr) {
        try {
            String resStr = posUtil.couponOrderIndependentVerify(posUrl, posDevId, posReqKey,
                    user.getTenantId(), String.valueOf(user.getMerchantId()), String.valueOf(user.getId()),
                    couponOrderIdStr, posOrderIdStr);
            if (resStr != null) {
                JSONObject retObj = JSON.parseObject(resStr);
                Map options = retObj;
                if (!WxPayment.verifyNotifyHMAC(options, posResKey)) {
                    return new ResultData(ErrorCode.PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR);
                } else {
                    return new ResultData(resStr);
                }
            } else {
                return new ResultData(Result.ERROR, "无返回值");
            }
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }
    }

    public ResultData posVerifyIndepent(WxMerchantBUser user, String couponOrderId, String payment) {
        // 1. 创建 POS订单
        PosOrder posOrder = new PosOrder();
        posOrder.setTenantId(user.getTenantId());
        posOrder.setType(EnumPosOrderType.VERIFY_INDEPENDENT.getCode());
        posOrder.setBuUserId(user.getId());
        posOrder.setOrderStatus(EnumPosOrderStatus.PENDING_VERIFY.getCode());
        posOrder.setPaymentType(EnumPosPayType.PAY_VERIFY_INDEPENT.getCode());
        if (StringUtils.isNotBlank(payment)) {
            posOrder.setPayment(Integer.valueOf(payment));
        }
        try {
            posOrderService.saveOrUpdate(posOrder);
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }
        // 2. 创建 POS支付订单
        Date curDate = new Date();
        PosPayOrder posPayOrder = new PosPayOrder();
        posPayOrder.setTenantId(user.getTenantId());
        posPayOrder.setBuUserId(user.getId());
        posPayOrder.setOrderId(posOrder.getId());
        posPayOrder.setType(EnumPosPayType.PAY_VERIFY_INDEPENT.getCode());
        posPayOrder.setPayTimeStart(curDate);
        posPayOrder.setPayTimeEnd(curDate);
        posPayOrder.setPayOrderNo(couponOrderId);
        posPayOrder.setPayOrderStatus(EnumPosOrderStatus.PENDING_VERIFY.getCode());
        posPayOrder.setCreateTime(curDate);
        posPayOrder.setUpdateTime(curDate);
        try {
            posPayOrderService.saveOrUpdate(posPayOrder);
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }

        // 3. POS支付订单支付
        try {
            couponOrderIndependentVerify(user, couponOrderId, posOrder.getPosOrderNo());
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }

        try {
            PosPayOrder updateOrder = new PosPayOrder();
            updateOrder.setId(posPayOrder.getId());
            updateOrder.setPayOrderStatus(EnumPosOrderStatus.VERIFY_SUCCESS.getCode());
            posPayOrderService.saveOrUpdate(posPayOrder);
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }

        // 4. POS订单支付
        try {
            PosOrder updateOrder = new PosOrder();
            updateOrder.setId(posOrder.getId());
            posOrder.setOrderStatus(EnumPosOrderStatus.VERIFY_SUCCESS.getCode());
            posOrderService.saveOrUpdate(posOrder);
        } catch (MallinkException e) {
            logger.error(e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new ResultData(Result.ERROR, e.getMessage());
        }
        // 5. 同步给fm pos进程
        // 5.1 posOrder信息
        PosOrder syncOrder = posOrderService.getById(posOrder.getId());
        if (syncOrder != null) {
            // 5.2 posPayOrder信息
            PosPayOrder q = new PosPayOrder();
            q.setOrderId(posOrder.getId());
            List<PosPayOrder> posPayOrders = posPayOrderService.getList(q);

        }

        return new ResultData();
    }
}
