package cn.ysk.cashier.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import cn.ysk.cashier.cons.RedisConstant;
import cn.ysk.cashier.cons.rabbit.RabbitConstants;
import cn.ysk.cashier.enums.OrderUseTypeEnum;
import cn.ysk.cashier.enums.TableStateEnum;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.model.ReturnOrderReq;
import cn.ysk.cashier.mybatis.entity.TbOrderPayment;
import cn.ysk.cashier.mybatis.mapper.*;
import cn.ysk.cashier.pojo.order.TbCashierCart;
import cn.ysk.cashier.pojo.order.TbOrderDetail;
import cn.ysk.cashier.pojo.order.TbOrderInfo;
import cn.ysk.cashier.pojo.shop.TbMerchantThirdApply;
import cn.ysk.cashier.pojo.shop.TbShopTable;
import cn.ysk.cashier.service.PayService;
import cn.ysk.cashier.thirdpay.constants.SignTypeEnum;
import cn.ysk.cashier.thirdpay.req.OrderRefundReq;
import cn.ysk.cashier.thirdpay.req.PublicParam;
import cn.ysk.cashier.thirdpay.resp.OrderReturnResp;
import cn.ysk.cashier.thirdpay.resp.OrderStatusQueryResp;
import cn.ysk.cashier.thirdpay.resp.PublicResp;
import cn.ysk.cashier.thirdpay.service.ThirdPayService;
import cn.ysk.cashier.utils.MD5Util;
import cn.ysk.cashier.utils.RabbitMsgUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.dianguang.cloud.ossservice.model.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
@Slf4j
public class PayServiceImpl implements PayService {

    private final MpMerchantThirdApplyMapper mpMerchantThirdApplyMapper;
    private final MpOrderPaymentMapper mpOrderPaymentMapper;
    private final ThirdPayService thirdPayService;
    private final TbCashierCartMapper tbCashierCartMapper;
    private final TbOrderDetailMapper tbOrderDetailMapper;
    private final TbOrderInfoMapper tbOrderInfoMapper;
    private final RabbitMsgUtils rabbitMsgUtils;
    private final RabbitTemplate rabbitTemplate;
    private final MpShopTableMapper mpShopTableMapper;
    @Value("${thirdPay.payType}")
    private String thirdPayType;
    @Value("${gateway.url}")
    private String gateWayUrl;
    @Value("${thirdPay.url}")
    private String url;
    @Value("${thirdPay.notify.fstReturn}")
    private String callBack;

    private final RestTemplate restTemplate;
    private final StringRedisTemplate redisTemplate;


    public PayServiceImpl(MpMerchantThirdApplyMapper mpMerchantThirdApplyMapper, RestTemplate restTemplate, MpOrderPaymentMapper mpOrderPaymentMapper, ThirdPayService thirdPayService, TbCashierCartMapper tbCashierCartMapper, TbOrderDetailMapper tbOrderDetailMapper, TbOrderInfoMapper tbOrderInfoMapper, RabbitMsgUtils rabbitMsgUtils, RabbitTemplate rabbitTemplate, MpShopTableMapper mpShopTableMapper, StringRedisTemplate redisTemplate) {
        this.mpMerchantThirdApplyMapper = mpMerchantThirdApplyMapper;
        this.restTemplate = restTemplate;
        this.mpOrderPaymentMapper = mpOrderPaymentMapper;
        this.thirdPayService = thirdPayService;
        this.tbCashierCartMapper = tbCashierCartMapper;
        this.tbOrderDetailMapper = tbOrderDetailMapper;
        this.tbOrderInfoMapper = tbOrderInfoMapper;
        this.rabbitMsgUtils = rabbitMsgUtils;
        this.rabbitTemplate = rabbitTemplate;
        this.mpShopTableMapper = mpShopTableMapper;
        this.redisTemplate = redisTemplate;
    }

    /**
     * 退款
     *
     * @param shopId 店铺id
     */
    @Override
    public void returnOrder(Integer shopId, TbOrderInfo orderInfo, TbOrderInfo returnOrderInfo) {
        TbMerchantThirdApply thirdApply = mpMerchantThirdApplyMapper.selectById(returnOrderInfo.getMerchantId());
        if (thirdApply == null) {
            throw new BadRequestException("支付参数未配置");
        }

        if ("ysk".equals(thirdPayType)) {
            ReturnOrderReq req = new ReturnOrderReq();
            req.setAppId(thirdApply.getAppId());
            req.setTimestamp(System.currentTimeMillis());
            req.setOrderNumber(orderInfo.getPayOrderNo());
            req.setAmount(String.format("%.2f", returnOrderInfo.getRefundAmount().setScale(2, RoundingMode.DOWN)));
            req.setMercRefundNo(orderInfo.getOrderNo());
            req.setRefundReason(StrUtil.isBlank(returnOrderInfo.getPayRemark()) ? "退货" : returnOrderInfo.getPayRemark());
            req.setPayPassword(thirdApply.getPayPassword());
            Map<String, Object> map = BeanUtil.beanToMap(req);
            req.setSign(MD5Util.encrypt(map, thirdApply.getAppToken(), true));
            log.info("银收客退款请求报文: {}", JSONUtil.toJsonStr(req));
            ResponseEntity<String> response = restTemplate.postForEntity(gateWayUrl.concat("merchantOrder/returnOrder"), req, String.class);
            log.info("银收客退款响应报文:{}", response.getBody());
            if (response.getStatusCodeValue() == 200 && ObjectUtil.isNotEmpty(response.getBody())) {
                JSONObject object = JSONObject.parseObject(response.getBody());
                if (!"0".equals(object.getString("code"))) {
                    throw new BadRequestException("退款渠道调用失败");
                }
            }
        } else {
            TbOrderPayment payment = mpOrderPaymentMapper.selectOne(new LambdaQueryWrapper<TbOrderPayment>()
                    .eq(TbOrderPayment::getShopId, shopId)
                    .eq(TbOrderPayment::getOrderId, orderInfo.getId()));
            log.info("福商通退款请求报文: {} {} {}", shopId, orderInfo, returnOrderInfo);
            PublicResp<OrderReturnResp> publicResp = thirdPayService.returnOrder(url, thirdApply.getAppId(),
                    returnOrderInfo.getOrderNo(), payment.getTradeNumber(), null, "订单退款",
                    returnOrderInfo.getRefundAmount().setScale(2, RoundingMode.DOWN).multiply(new BigDecimal(100)).longValue(), callBack, null, thirdApply.getAppToken());
            log.info("福商通退款响应报文: {}", publicResp);
            if (ObjectUtil.isNotNull(publicResp) && ObjectUtil.isNotEmpty(publicResp)) {
                if ("000000".equals(publicResp.getCode())) {
                    if (!"SUCCESS".equals(publicResp.getObjData().getState()) && !publicResp.getObjData().getState().equals("ING")) {
                        throw new BadRequestException("退款渠道调用失败: " + publicResp.getMsg());
                    }
                } else {
                    throw new BadRequestException("退款渠道调用失败: " + publicResp.getMsg());
                }
            }
        }
    }


    @Override
    public boolean checkPayState(TbOrderInfo orderInfo) {

        if ("paying".equals(orderInfo.getStatus())) {
            TbOrderPayment payment = mpOrderPaymentMapper.selectOne(new LambdaQueryWrapper<TbOrderPayment>()
                    .eq(TbOrderPayment::getOrderId, orderInfo.getId()));
            if (ObjectUtil.isNotEmpty(payment) && ObjectUtil.isNotEmpty(payment.getTradeNumber())) {

                TbMerchantThirdApply thirdApply = mpMerchantThirdApplyMapper.selectById(Integer.valueOf(orderInfo.getMerchantId()));

                if (ObjectUtil.isEmpty(thirdApply) || ObjectUtil.isNull(thirdApply)) {
                   throw new BadRequestException("三方支付信息不存在");
                }

                PublicResp<OrderStatusQueryResp> publicResp = thirdPayService.queryOrder(url, thirdApply.getAppId(),
                        payment.getTradeNumber(), null, thirdApply.getAppToken());
                if (ObjectUtil.isNotNull(publicResp) && ObjectUtil.isNotEmpty(publicResp)) {
                    if ("000000".equals(publicResp.getCode())) {
                        String cartStatus = "";
                        switch (publicResp.getObjData().getState()) {
                            case "TRADE_SUCCESS":
                                //修改数据库中购物车数据
                                int cartCount = tbCashierCartMapper.update(null, new LambdaUpdateWrapper<TbCashierCart>()
                                        .eq(TbCashierCart::getOrderId, orderInfo.getId())
                                        .eq(TbCashierCart::getUseType, orderInfo.getUseType())
                                        .in(TbCashierCart::getStatus, "create", "closed")
                                        .set(TbCashierCart::getStatus, "final"));
                                log.info("更新购物车:{}", cartCount);

                                //更新子单状态
                                tbOrderDetailMapper.update(null, new LambdaUpdateWrapper<TbOrderDetail>()
                                        .eq(TbOrderDetail::getOrderId, orderInfo.getId())
                                        .eq(TbOrderDetail::getUseType, orderInfo.getUseType())
                                        .in(TbOrderDetail::getStatus, "unpaid")
//                                        .setSql(StrUtil.format("price_amount=price*num*{}", orderInfo.getDiscountRatio() == null ? 1 : orderInfo.getDiscountRatio()))
                                        .set(TbOrderDetail::getStatus, "closed"));

                                //修改主单状态
                                orderInfo.setStatus("closed");
                                orderInfo.setPayOrderNo(payment.getTradeNumber());
//                                orderInfo.setPayAmount(orderInfo.getOrderAmount());
                                orderInfo.setPaidTime(System.currentTimeMillis());
                                tbOrderInfoMapper.updateById(orderInfo);


                                // 打印消息
                                if (!OrderUseTypeEnum.DINE_IN_AFTER.getValue().equals(orderInfo.getUseType())){
                                    List<TbOrderDetail> detailList = tbOrderDetailMapper.selectList(new LambdaQueryWrapper<TbOrderDetail>()
                                            .eq(TbOrderDetail::getOrderId, orderInfo.getId())
                                            .eq(TbOrderDetail::getStatus, "closed"));
                                    rabbitMsgUtils.printDishesTicket(orderInfo.getId(), false, detailList.toArray(new TbOrderDetail[0]));
                                }
                                rabbitMsgUtils.printPlaceTicket(orderInfo.getId(), false);

                                // 发送库存记录mq消息
                                JSONObject mqData = new JSONObject();
                                mqData.put("orderId", orderInfo.getId());
                                mqData.put("type", "pc");
                                rabbitTemplate.convertAndSend(RabbitConstants.EXCHANGE_STOCK_RECORD, RabbitConstants.ROUTING_STOCK_RECORD_SALE, mqData.toJSONString(), new CorrelationData(UUID.randomUUID().toString()));

                                // 修改台桌状态
                                if (!OrderUseTypeEnum.TAKEOUT.getValue().equals(orderInfo.getUseType())) {
                                    TbShopTable tbShopTable = mpShopTableMapper.selectOne(new LambdaQueryWrapper<TbShopTable>()
                                            .eq(TbShopTable::getShopId, orderInfo.getShopId())
                                            .eq(TbShopTable::getQrcode, orderInfo.getTableId()));
                                    if (tbShopTable.getAutoClear().equals(1)) {
                                        mpShopTableMapper.update(null, new LambdaUpdateWrapper<TbShopTable>()
                                                .eq(TbShopTable::getQrcode, orderInfo.getTableId())
                                                .set(TbShopTable::getEndTime, DateUtil.date())
                                                .set(TbShopTable::getUseNum, 0)
                                                .set(TbShopTable::getStatus, TableStateEnum.IDLE.getState()));
                                    } else {
                                        mpShopTableMapper.update(null, new LambdaUpdateWrapper<TbShopTable>()
                                                .eq(TbShopTable::getQrcode, orderInfo.getTableId())
                                                .set(TbShopTable::getEndTime, DateUtil.date())
                                                .set(TbShopTable::getStatus, TableStateEnum.CLEANING.getState()));
                                    }

                                    String day = DateUtils.getDay();
                                    String key = "SHOP:CODE:USER:pc" + ":" + orderInfo.getShopId() + ":" + day + ":" + orderInfo.getTableId();
                                    redisTemplate.delete(key);
                                }

                                String currentOrderKey = RedisConstant.CURRENT_TABLE_ORDER + orderInfo.getShopId() + ":" + orderInfo.getTableId();
                                redisTemplate.delete(currentOrderKey);

                                // 小程序购物车缓存
                                String tableCartKey = RedisConstant.getTableCartKey(orderInfo.getTableId(), orderInfo.getShopId());
                                redisTemplate.delete(tableCartKey);

                                return true;
                            case "REFUND_ING":
                                cartStatus = "refunding";
                                orderInfo.setStatus("refunding");
                                break;
                        }
                    }
                }

            }
        }
        return false;
    }


}
