package com.kxs.product.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.alipay.api.AlipayApiException;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kxs.common.core.constant.CommonConstants;
import com.kxs.common.core.constant.SecurityConstants;
import com.kxs.common.core.exception.GlobalCustomerException;
import com.kxs.common.core.util.R;
import com.kxs.common.mq.handlers.IMQSender;
import com.kxs.common.pay.enums.PayPlatformEnum;
import com.kxs.common.pay.enums.PayStatusCommEnum;
import com.kxs.common.pay.factory.PaymentFactory;
import com.kxs.common.pay.model.*;
import com.kxs.common.security.util.SecurityUtils;
import com.kxs.product.api.amqp.rabbit.RabbitShopTimeoutQueueMQ;
import com.kxs.product.api.dto.kxsapp.shop.GoodsSubmitDTO;
import com.kxs.product.api.dto.kxsapp.shop.PayOrderDTO;
import com.kxs.product.api.model.*;
import com.kxs.product.api.vo.kxsapp.shop.*;
import com.kxs.product.biz.constant.enums.KxsShopEnum;
import com.kxs.product.biz.constant.enums.ProductErrorTypeEnum;
import com.kxs.product.biz.constant.enums.TicketTypeEnum;
import com.kxs.product.biz.mapper.*;
import com.kxs.product.biz.service.KxsShopOrderService;
import com.kxs.product.biz.service.KxsTicketService;
import com.kxs.store.api.feign.RemoteKxsStoreService;
import com.kxs.store.api.model.KxsWarehouseLimit;
import com.kxs.system.api.util.ParamResolver;
import com.kxs.user.api.feign.RemoteKxsUserService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 商城订单表(KxsShopOrder)表服务实现类
 *
 * @author 系统
 * @since 2023-12-20 10:09:35
 */
@Service("kxsShopOrderService")
@RequiredArgsConstructor
@Slf4j
public class KxsShopOrderServiceImpl extends ServiceImpl<KxsShopOrderMapper, KxsShopOrder> implements KxsShopOrderService {

    private final KxsShopGoodsMapper goodsMapper;

    private final KxsShopOrderInfoMapper orderInfoMapper;

    private final RemoteKxsUserService remoteKxsUserService;

    private final PaymentFactory paymentFactory;

    private final KxsShopGoodsSkuMapper kxsShopGoodsSkuMapper;

    private final KxsTicketService kxsTicketService;

    private final IMQSender mqSender;

    private final KxsShopGoodsMapper kxsShopGoodsMapper;

    private final RemoteKxsStoreService remoteKxsStoreService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public R submitOrder(GoodsSubmitDTO param) {

        Long userId = SecurityUtils.getUser().getId();

        //订单号
        String orderSn = CommonConstants.KXS_SHOP_PREFIX + IdUtil.getSnowflakeNextIdStr();

        //查询商品
        KxsShopGoods goods = goodsMapper.selectById(param.getGoodsId());
        Optional.ofNullable(goods).orElseThrow(() -> new GlobalCustomerException("商品不存在"));
        //查询商品sku
        KxsShopGoodsSku kxsShopGoodsSku = kxsShopGoodsSkuMapper.selectById(param.getSkuId());
        Optional.ofNullable(kxsShopGoodsSku).orElseThrow(() -> new GlobalCustomerException("商品sku不存在"));
        BigDecimal totalPrice = kxsShopGoodsSku.getPrice().multiply(new BigDecimal(param.getNumber()));
        if (totalPrice.compareTo(param.getTotalPrice()) != 0) {
            return R.failed("订单金额不一致");
        }

        KxsShopOrder order = new KxsShopOrder();
        //参数赋值
        BeanUtils.copyProperties(param, order);
        order.setUserId(userId);
        order.setOrderSn(orderSn);
        //支付金额
        order.setPayPrice(order.getTotalPrice());
        baseMapper.insert(order);


        //当sku库存不为null时需做存量校验
        if (kxsShopGoodsSku.getStockNum() != null && kxsShopGoodsSku.getStockNum() != -1) {
            int i = kxsShopGoodsSku.getStockNum() - param.getNumber();
            if (i < 0) {
                throw new GlobalCustomerException("当前库存不足");
            }
            kxsShopGoodsSku.setStockNum(i);
            //修改库存
            kxsShopGoodsSkuMapper.updateById(kxsShopGoodsSku);
        }
        //校验是否存在起购以及限购数量校验
        if (kxsShopGoodsSku.getStartByCount() != null && kxsShopGoodsSku.getStartByCount() != 0) {
            boolean b = kxsShopGoodsSku.getStartByCount() > param.getNumber();
            if (b) {
                throw new GlobalCustomerException("该商品最低" + kxsShopGoodsSku.getStartByCount() + "件起购");
            }
        } else if (kxsShopGoodsSku.getLimitCount() != null && kxsShopGoodsSku.getLimitCount() != 0) {
            boolean b = kxsShopGoodsSku.getLimitCount() < param.getNumber();
            if (b) {
                throw new GlobalCustomerException("该商品每人最多购买" + kxsShopGoodsSku.getLimitCount() + "件");
            }
        }
        //订单详情
        KxsShopOrderInfo orderInfo = new KxsShopOrderInfo();
        orderInfo.setNumber(param.getNumber());
        orderInfo.setGoodsId(param.getGoodsId());
        orderInfo.setSkuId(kxsShopGoodsSku.getId());
        orderInfo.setSpecifications(kxsShopGoodsSku.getSpecifications());
        orderInfo.setGoodsName(goods.getGoodsName());
        orderInfo.setGoodsPrice(goods.getPrice());
        orderInfo.setPicUrl(goods.getPicUrl());
        orderInfo.setOrderId(order.getId());
        orderInfoMapper.insert(orderInfo);

        //发送订单延时取消消息
        RabbitShopTimeoutQueueMQ.MsgEntity msgEntity = new RabbitShopTimeoutQueueMQ.MsgEntity();
        BeanUtils.copyProperties(order, msgEntity);
        mqSender.send(RabbitShopTimeoutQueueMQ.build(msgEntity), 60 * 20);
        return R.ok(order.getId());

    }

    @Override
    public ShopOrderDetailVO getByOrderId(Integer orderId) {

        KxsShopOrder order = baseMapper.selectById(orderId);
        if (order == null) {
            return null;
        }
        ShopOrderDetailVO shopOrderDetailVO = new ShopOrderDetailVO();
        BeanUtils.copyProperties(order, shopOrderDetailVO);

        List<KxsShopOrderInfo> orderInfos = orderInfoMapper.selectList(Wrappers.<KxsShopOrderInfo>lambdaQuery()
                .eq(KxsShopOrderInfo::getOrderId, orderId));

        orderInfos.forEach(item -> {
            //商品实物或虚拟物品标识
            KxsShopGoods kxsShopGoods = kxsShopGoodsMapper.selectById(item.getGoodsId());
            ShopOrderInfoListVO infoListVO = new ShopOrderInfoListVO();
            BeanUtil.copyProperties(item, infoListVO);
            infoListVO.setGoodsType(kxsShopGoods.getGoodsType());
            shopOrderDetailVO.getGoodsList().add(infoListVO);
        });
        //机具券集合
        List<KxsTicket> kxsTickets = kxsTicketService.list(Wrappers.<KxsTicket>lambdaQuery().eq(KxsTicket::getOrderId, orderId));
        shopOrderDetailVO.setTicketCodes(kxsTickets.stream().map(KxsTicket::getTicketCode).collect(Collectors.toList()));

        return shopOrderDetailVO;
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public R payOrder(PayOrderDTO param) {

        if (param.getId() == null) {
            return R.failed(ProductErrorTypeEnum.ORDER_EMPTY.getDescription());
        }
        if (param.getPayType() == null) {
            return R.failed("请选择支付方式");
        }
        KxsShopOrder order = baseMapper.selectById(param.getId());
        if (order == null) {
            return R.failed(ProductErrorTypeEnum.ORDER_EMPTY.getDescription());
        }
        if (!Objects.equals(order.getStatus(), KxsShopEnum.ORDER_NO_PAY.getType())) {
            return R.failed(ProductErrorTypeEnum.ORDER_STATUS_ERROR.getDescription());
        }

        //校验支付方式,邮寄需要
        if (Objects.equals(param.getGetMode(), KxsShopEnum.ORDER_ERP.getType())) {
            order.setGetMode(param.getGetMode());
            order.setPhone(param.getPhone());
            order.setConsignee(param.getConsignee());
            order.setAddress(param.getAddress());
            order.setPayType(param.getPayType());
            order.setRemark(param.getRemark());
            //修改订单地址
            updateById(order);
        } else {
            order.setGetMode(param.getGetMode());
            order.setPayType(param.getPayType());
            order.setRemark(param.getRemark());
            updateById(order);
        }
        List<KxsShopOrderInfo> kxsShopOrderInfos = orderInfoMapper.selectList(Wrappers.<KxsShopOrderInfo>lambdaQuery().eq(KxsShopOrderInfo::getOrderId, order.getId()));
        String subject = kxsShopOrderInfos.stream().map(KxsShopOrderInfo::getGoodsName).collect(Collectors.joining(","));

        //支付宝支付
        if (param.getPayType().equals(KxsShopEnum.ALI_PAY.getType())) {
            return this.aliPay(order, subject);
        }

        //余额支付
        if (param.getPayType().equals(KxsShopEnum.YUE_PAY.getType())) {

            //校验支付密码
            R<Boolean> booleanR = remoteKxsUserService.checkPayPwd(param.getPayPwd());
            if (booleanR.getStatus() != 1 || !booleanR.getData()) {
                throw new GlobalCustomerException("支付密码错误");
            }

            PayRequest payReq = new PayRequest();
            payReq.setPayTypeEnum(PayPlatformEnum.YUEPAY);
            payReq.setOutTradeNo(order.getOrderSn());
            payReq.setSubject(subject);
            payReq.setTotalAmount(order.getPayPrice().doubleValue());
            try {
                PayResponse payResponse = paymentFactory.getPayService(PayPlatformEnum.YUEPAY.getType()).appPay(payReq);

                YuePayMessage payMessage = BeanUtil.toBean(payResponse.getResult(), YuePayMessage.class);
                if (payMessage != null) {
                    //支付成功回调
                    this.payBack(order.getOrderSn());
                } else {
                    throw new GlobalCustomerException("余额支付异常");
                }
            } catch (Exception e) {
                log.error("订单号{}余额支付异常:{}", order.getOrderSn(), e.getMessage(), e);
                throw new GlobalCustomerException(e.getMessage());
            }
        }

        return R.ok();
    }


    @Override
    public void payBack(String outTradeNo) {
        KxsShopOrder order = baseMapper.selectOne(Wrappers.<KxsShopOrder>lambdaQuery().eq(KxsShopOrder::getOrderSn, outTradeNo).last("FOR UPDATE"));
        if (order == null) {
            throw new GlobalCustomerException("订单支付回调未找到订单号：" + outTradeNo);
        }
        if (!Objects.equals(order.getStatus(), KxsShopEnum.ORDER_NO_PAY.getType())) {
            throw new GlobalCustomerException("订单支付回调状态错误订单号：" + outTradeNo);
        }
        order.setStatus(KxsShopEnum.ORDER_NO_SEND.getType());
        order.setPayTime(LocalDateTime.now());
        List<KxsShopOrderInfo> kxsShopOrderInfos = orderInfoMapper.selectList(Wrappers.<KxsShopOrderInfo>lambdaQuery().eq(KxsShopOrderInfo::getOrderId, order.getId()));
        //目前只能下单一个商品，故直接取之
        KxsShopOrderInfo kxsShopOrderInfo = kxsShopOrderInfos.get(0);
        Integer dqGoodsId = ParamResolver.getInteger("DQ_GOODS_ID", 10);
        Integer djGoodsId = ParamResolver.getInteger("DJ_GOODS_ID", 11);
        Integer preLimitGoodsId100 = ParamResolver.getInteger("PRE_LIMIT_GOODS_ID_100", 58);
        Integer preLimitGoodsId500 = ParamResolver.getInteger("PRE_LIMIT_GOODS_ID_500", 57);
        Integer preLimitGoodsId1000 = ParamResolver.getInteger("PRE_LIMIT_GOODS_ID_1000", 56);
        Integer storeForLimit2000 = ParamResolver.getInteger("STORE_FOR_LIMIT_2000", 30);
        Integer storeForLimit10000 = ParamResolver.getInteger("STORE_FOR_LIMIT_10000", 31);
        Integer storeForLimit20000 = ParamResolver.getInteger("STORE_FOR_LIMIT_20000", 32);
        //电签
        if (Objects.equals(kxsShopOrderInfo.getGoodsId(), dqGoodsId)) {
            if (!kxsTicketService.userBuyTicket(order.getUserId(), TicketTypeEnum.CODE_DQ.getType(), order.getId(), kxsShopOrderInfo.getNumber() * 3)) {
                throw new GlobalCustomerException("兑换电签机具券失败订单号：" + outTradeNo);
            }
        }
        //大机
        if (Objects.equals(kxsShopOrderInfo.getGoodsId(), djGoodsId)) {
            if (!kxsTicketService.userBuyTicket(order.getUserId(), TicketTypeEnum.CODE_DJ.getType(), order.getId(), kxsShopOrderInfo.getNumber() * 2)) {
                throw new GlobalCustomerException("兑换大机机具券失败订单号：" + outTradeNo);
            }
        }
        //小分仓预发额度
        if (Objects.equals(kxsShopOrderInfo.getGoodsId(), preLimitGoodsId100)
                || Objects.equals(kxsShopOrderInfo.getGoodsId(), preLimitGoodsId500)
                || Objects.equals(kxsShopOrderInfo.getGoodsId(), preLimitGoodsId1000)) {

            addForLimit(order, 1);
        }
        //仓库临时额度
        if (Objects.equals(kxsShopOrderInfo.getGoodsId(), storeForLimit2000)
                || Objects.equals(kxsShopOrderInfo.getGoodsId(), storeForLimit10000)
                || Objects.equals(kxsShopOrderInfo.getGoodsId(), storeForLimit20000)) {

            addForLimit(order, 0);
        }

        KxsShopGoods goods = kxsShopGoodsMapper.selectById(kxsShopOrderInfo.getGoodsId());
        //虚拟商品改为已完成
        if (Objects.equals(goods.getGoodsType(), KxsShopEnum.GOODS_VIRTUAL.getType())) {
            order.setStatus(KxsShopEnum.ORDER_CONFIRM.getType());
        }

        this.updateById(order);

    }

    @Async
    @Override
    public void shopOrderTimeout() {
        List<KxsShopOrder> list = list(Wrappers.<KxsShopOrder>lambdaQuery()
                .eq(KxsShopOrder::getStatus, KxsShopEnum.ORDER_NO_PAY.getType())
                .lt(KxsShopOrder::getCreateTime, LocalDateTime.now().minusMinutes(21)).last("limit 10"));

        for (KxsShopOrder order : list) {
            if (order.getStatus().equals(KxsShopEnum.ORDER_NO_PAY.getType())) {
                changeTimeoutOrder(order);
            }
        }

    }

    @Override
    public void changeTimeoutOrder(KxsShopOrder order) {

        order.setStatus(KxsShopEnum.ORDER_CANCEL.getType());

        QueryResponse query = null;
        QueryRequest queryReq = QueryRequest.builder()
                .outTradeNo(order.getOrderSn())
                .build();
        if (order.getPayType().equals(KxsShopEnum.ALI_PAY.getType())) {
            query = paymentFactory.getPayService(PayPlatformEnum.ALIPAY.getType()).query(queryReq);
        }
        if (order.getPayType().equals(KxsShopEnum.WECHAT_PAY.getType())) {
            query = paymentFactory.getPayService(PayPlatformEnum.WX.getType()).query(queryReq);
        }
        if (query != null) {
            order.setStatus(PayStatusCommEnum.TRADE_SUCCESS == query.getTradeStatus() ? KxsShopEnum.ORDER_NO_SEND.getType() : KxsShopEnum.ORDER_CANCEL.getType());
        }
        updateById(order);
    }

    /**
     * 添加临时额度
     *
     * @param order         订单
     * @param warehouseType 仓库类型 0分仓 1小分仓
     */
    private void addForLimit(KxsShopOrder order, int warehouseType) {

        BigDecimal totalPrice = order.getTotalPrice();
        if (warehouseType == 0) {
            totalPrice = totalPrice.multiply(new BigDecimal(2));
        }

        KxsWarehouseLimit kxsWarehouseLimit = new KxsWarehouseLimit();
        kxsWarehouseLimit.setUserId(order.getUserId().intValue());
        kxsWarehouseLimit.setWarehouseType(warehouseType);
        if (Objects.equals(order.getPayType(), KxsShopEnum.YUE_PAY.getType())) {
            kxsWarehouseLimit.setYueForAmount(totalPrice);
        }
        if (Objects.equals(order.getPayType(), KxsShopEnum.ALI_PAY.getType())) {
            kxsWarehouseLimit.setForAmount(totalPrice);
        }
        R<Boolean> booleanR = remoteKxsStoreService.addForAmount(kxsWarehouseLimit, SecurityConstants.FROM_IN);
        if (!booleanR.getData()) {
            throw new GlobalCustomerException("新增临时额度失败订单号：" + order.getOrderSn());
        }
    }


    @Override
    public R cancelOrder(KxsShopOrder param) {

        KxsShopOrder order = baseMapper.selectById(param.getId());
        if (order == null) {
            return R.failed(ProductErrorTypeEnum.ORDER_EMPTY.getDescription());
        }
        if (!order.getStatus().equals(KxsShopEnum.ORDER_NO_PAY.getType())) {
            return R.failed(ProductErrorTypeEnum.ORDER_NO_CANCEL.getDescription());
        }
        order.setStatus(KxsShopEnum.ORDER_CANCEL.getType());
        baseMapper.updateById(order);

        return R.ok();
    }

    @Override
    public R confirmOrder(KxsShopOrder param) {

        KxsShopOrder order = baseMapper.selectById(param.getId());
        if (order == null) {
            return R.failed(ProductErrorTypeEnum.ORDER_EMPTY.getDescription());
        }
        if (!order.getStatus().equals(KxsShopEnum.ORDER_NO_TAKE.getType())) {
            return R.failed(ProductErrorTypeEnum.ORDER_NO_CONFIRM.getDescription());
        }
        order.setStatus(KxsShopEnum.ORDER_CONFIRM.getType());
        baseMapper.updateById(order);

        return R.ok();
    }

    @Override
    public IPage<ShopOrderListVO> getByPage(Page<ShopOrderListVO> page, KxsShopOrder param) {

        Long userId = SecurityUtils.getUser().getId();
        param.setUserId(userId);
        //自定义分页
        long start = (page.getCurrent() - 1) * page.getSize();
        start = start < 0 ? 0L : start;

        Long count = baseMapper.selectCount(Wrappers.query(param));
        List<ShopOrderListVO> orderListVos = baseMapper.getByPage(start, page.getSize(), param);
        page.setRecords(orderListVos);
        page.setTotal(count);

        return page;
    }

    @Override
    public ShopOrderCountVO orderUnCount() {

        Long userId = SecurityUtils.getUser().getId();

        Long noPayCount = baseMapper.selectCount(Wrappers.<KxsShopOrder>lambdaQuery()
                .eq(KxsShopOrder::getUserId, userId)
                .eq(KxsShopOrder::getStatus, KxsShopEnum.ORDER_NO_PAY.getType()));
        Long noSendCount = baseMapper.selectCount(Wrappers.<KxsShopOrder>lambdaQuery()
                .eq(KxsShopOrder::getUserId, userId)
                .eq(KxsShopOrder::getStatus, KxsShopEnum.ORDER_NO_SEND.getType()));

        return ShopOrderCountVO.builder().needPayCount(noPayCount).needSendCount(noSendCount).build();
    }

    @Override
    public List<ShopOrderGoodsUserVO> getDateBetweenOrders(String startTime, String endTime) {

        return baseMapper.getDateBetweenOrders(startTime, endTime);

    }


    /**
     * 支付宝支付
     *
     * @param param   参数
     * @param subject 订单标题。
     * @return {@link R}
     */
    private R aliPay(KxsShopOrder param, String subject) {

        PayRequest payReq = new PayRequest();
        payReq.setPayTypeEnum(PayPlatformEnum.ALIPAY);
        payReq.setOutTradeNo(param.getOrderSn());
        payReq.setSubject(subject);
        payReq.setTotalAmount(param.getPayPrice().doubleValue());
        //扩展参数
        payReq.setPassbackParams(CommonConstants.SHOP_ORDER_FLAG);

        PayResponse payResponse = paymentFactory.getPayService(PayPlatformEnum.ALIPAY.getType()).appPay(payReq);

        return R.ok(payResponse);
    }


}

