package org.springblade.modules.api.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springblade.common.constant.CacheBizConstant;
import org.springblade.common.enums.AuditStatusEnum;
import org.springblade.common.enums.OrderStateEnum;
import org.springblade.common.enums.PaymentTypeEnum;
import org.springblade.common.enums.YesOrNoEnum;
import org.springblade.common.utils.DistanceUtils;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.modules.api.request.Goods;
import org.springblade.modules.api.request.GroupOrderRequest;
import org.springblade.modules.api.request.SubmitOrderRequest;
import org.springblade.modules.api.response.GoodsResponse;
import org.springblade.modules.api.response.GrouponOrderResponse;
import org.springblade.modules.api.service.SubmitOrderService;
import org.springblade.modules.distribution.service.ICommissionService;
import org.springblade.modules.finance.entity.ConfirmOrder;
import org.springblade.modules.finance.entity.Order;
import org.springblade.modules.finance.entity.OrderGroupon;
import org.springblade.modules.finance.entity.OrderGrouponGoods;
import org.springblade.modules.finance.service.*;
import org.springblade.modules.finance.service.impl.OrderTimeoutService;
import org.springblade.modules.groupon.entity.*;
import org.springblade.modules.groupon.service.*;
import org.springblade.modules.groupon.vo.SelfTakeVO;
import org.springblade.modules.groupon.wrapper.SelfTakeWrapper;
import org.springblade.modules.mall.entity.GoodsInfo;
import org.springblade.modules.mall.service.IGoodsInfoService;
import org.springblade.modules.platform.service.IMessageService;
import org.springblade.modules.platform.service.UserAppService;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.entity.UserApp;
import org.springblade.modules.system.entity.UserWeChat;
import org.springblade.modules.system.service.IUserService;
import org.springblade.modules.system.service.IUserWeChatService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Author pangqijun
 * Date 2023/6/6
 * Description
 */
@Service("grouponOrderServiceImpl")
public class GrouponOrderServiceImpl implements SubmitOrderService {

    @Resource
    private IOrderService orderService;
    @Resource
    private IGoodsInfoService goodsInfoService;
    @Resource
    private IGrouponService grouponService;
    @Resource
    private IGrouponGoodsService grouponGoodsService;
    @Resource
    private IOrderGrouponService orderGrouponService;
    @Resource
    private IOrderGrouponGoodsService orderGrouponGoodsService;
    @Resource
    private OrderTimeoutService orderTimeoutService;
    @Resource
    private IGrouponUserService grouponUserService;
    @Resource
    private IUserService userService;
    @Resource
    private IUserWeChatService userWeChatService;
    @Resource
    private IWxPayService wxPayService;
    @Resource
    private ISelfTakeService selfTakeService;
    @Resource
    private IConfirmOrderService confirmOrderService;
    @Resource
    private IMessageService messageService;
    @Resource
    private ICommissionService commissionService;
    @Resource
    private IUserSelfTakeService userSelfTakeService;
    @Resource
    private IEmbersService embersService;
    @Resource
    private BladeRedis bladeRedis;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String submitOrder(SubmitOrderRequest request) {
        Assert.notEmpty(request.getGoodsInfos(), "请选择商品");
        Assert.notNull(request.getGrouponId(), "团购ID不能为空");
        Assert.notNull(request.getSelfTakeId(), "自提点id不能为空");
        User user = userService.getById(request.getUserId());
        Assert.notNull(user, "未查询到用户数据");

        Groupon groupon = grouponService.getById(request.getGrouponId());
        List<Goods> collect = request.getGoodsInfos().stream().filter(e -> e.getNum() > 0).collect(Collectors.toList());
        // 校验拼团
        this.checkGroupon(groupon);

        List<Long> goodsIds = collect.stream().map(Goods::getGoodsId).collect(Collectors.toList());
        Assert.notEmpty(goodsIds, "请选择商品");
        // 查询团购商品数据
        List<GrouponGoods> grouponGoods = grouponGoodsService.lambdaQuery().eq(GrouponGoods::getGrouponId, groupon.getId()).in(GrouponGoods::getGoodsId, goodsIds).list();
        // 查询商品数据
        List<GoodsInfo> goodsInfos = goodsInfoService.lambdaQuery().in(GoodsInfo::getId, goodsIds).list();
        Assert.notEmpty(goodsIds, "未查询到商品数据");
        Map<Long, GoodsInfo> map = goodsInfos.stream().collect(Collectors.toMap(GoodsInfo::getId, Function.identity()));

        Order order = orderService.init();
        order.setUserId(request.getUserId());
        order.setOrderType(request.getOrderType());
        order.setSource(request.getOrderSource());
        order.setDiscountAmount(BigDecimal.valueOf(0));
        order.setCreateUserId(request.getUserId());

        Map<Long, Integer> goodsNumMap = collect.stream().collect(Collectors.toMap(Goods::getGoodsId, Goods::getNum));
        // 计算商品总价
        BigDecimal total = BigDecimal.valueOf(0);
        for (GrouponGoods g : grouponGoods) {
            total = total.add(g.getGrouponPrice().multiply(BigDecimal.valueOf(goodsNumMap.get(g.getGoodsId()))));
        }
        order.setTotalAmount(total);
        order.setPaymentAmount(total.subtract(order.getDiscountAmount()));
        orderService.save(order);

        // 保存团购订单数据
        this.saveGrouponOrder(order, request, groupon);

        // 保存团购商品数据
        this.saveGrouponGoodsOrder(order, map, collect, grouponGoods);

        // 添加订单到延时队列，处理订单支付超时问题
        orderTimeoutService.addTask(order.getId(), null);

        return order.getOrderNo();
    }

    @Override
    @Transactional
    public void confirmOrder(String pickupCode, Long userId) {
        OrderGroupon one = orderGrouponService.getOne(Wrappers.lambdaQuery(OrderGroupon.class).
                eq(OrderGroupon::getIsChargeOff, YesOrNoEnum.NO.getValue()).eq(OrderGroupon::getPickupCode, pickupCode));
        Assert.notNull(one, "取货码数据不存在");
        UserSelfTake selfTake = userSelfTakeService.lambdaQuery().eq(UserSelfTake::getUserId, userId).one();
        Assert.notNull(selfTake, "未查询到团长绑定的自提点数据");
        // 需校验自提点跟团长是否符合
        if (!one.getSelfTakeId().equals(selfTake.getSelfTakeId())) {
            throw new ServiceException("核销自提点不再团长负责范围内");
        }
        if (!YesOrNoEnum.YES.getValue().equals(one.getIsArrive())) {
            throw new ServiceException("商品未到货");
        }
        one.setIsChargeOff(YesOrNoEnum.YES.getValue());
        orderGrouponService.updateById(one);
        Order order = orderService.getById(one.getOrderId());
        order.setOrderState(OrderStateEnum.COMPLETED.getValue());
        orderService.updateById(order);
        ConfirmOrder confirmOrder = new ConfirmOrder();
        confirmOrder.setOrderId(one.getOrderId());
        confirmOrder.setPickupCode(pickupCode);
        confirmOrderService.save(confirmOrder);
        messageService.sendMessage(order.getUserId(), "提货成功", order.getOrderNo());
    }

    @Override
    public List<OrderGrouponGoods> getGroupGoodsList(Long orderId) {
        return orderGrouponGoodsService.list(Wrappers.lambdaQuery(OrderGrouponGoods.class)
                .eq(OrderGrouponGoods::getOrderId, orderId));
    }

    /**
     * 校验商品
     * @param map
     * @param goodsInfos
     */
    private void checkGoods(Map<Long, GoodsInfo> map, List<Goods> goodsInfos) {
        for (Goods goodsInfo : goodsInfos) {
            GoodsInfo info = map.get(goodsInfo.getGoodsId());
            Long size = bladeRedis.lLen(CacheBizConstant.GOODS_STORE + info.getId());
            if (size < goodsInfo.getNum()) {
                throw new ServiceException(String.format("%s库存不足", info.getGoodsName()));
            }
        }
    }

    /**
     * 校验拼团信息
     * @param groupon
     */
    private void checkGroupon(Groupon groupon) {
        Assert.notNull(groupon, "未查询到团购数据");
        if (!(AuditStatusEnum.PASS.getValue().equals(groupon.getAuditStatus())) || YesOrNoEnum.NO.getValue().equals(groupon.getStatus())) {
            throw new ServiceException("拼团状态异常");
        }
        LocalDateTime now = LocalDateTime.now();
        if (groupon.getGrouponEndTime().isBefore(now)) {
            throw new ServiceException("拼团已结束");
        }
        if (groupon.getGrouponStartTime().isAfter(now)) {
            throw new ServiceException("拼团未开始");
        }
    }

    /**
     * 保存团购订单数据
     * @param order
     * @param request
     */
    private void saveGrouponOrder(Order order, SubmitOrderRequest request, Groupon groupon) {
        OrderGroupon o = new OrderGroupon();
        o.setGrouponId(groupon.getId());
        o.setOrganizerId(groupon.getOrganizerUserId());
        o.setOrderId(order.getId());
        o.setSelfTakeId(request.getSelfTakeId());
        o.setPickupCode(RandomUtil.randomStringUpper(6));
        o.setIsArrive(YesOrNoEnum.NO.getValue());
        o.setIsChargeOff(YesOrNoEnum.NO.getValue());
        orderGrouponService.save(o);
    }

    /**
     * 保存团购商品数据
     */
    private void saveGrouponGoodsOrder(Order order, Map<Long, GoodsInfo> map, List<Goods> requestGoods, List<GrouponGoods> grouponGoods) {
        Map<Long, GrouponGoods> collect = grouponGoods.stream().collect(Collectors.toMap(GrouponGoods::getGoodsId, Function.identity()));
        List<OrderGrouponGoods> list = new ArrayList<>();
        List<GoodsInfo> goods = new ArrayList<>();
        // 校验商品库存
        this.checkGoods(map, requestGoods);

        for (Goods g : requestGoods) {
            GrouponGoods gg = collect.get(g.getGoodsId());
            GoodsInfo goodsInfo = map.get(g.getGoodsId());
            OrderGrouponGoods o = new OrderGrouponGoods(order.getId(), goodsInfo.getId(), g.getNum(),
                    gg.getGrouponPrice(), goodsInfo.getGoodsName(), goodsInfo.getGoodsCover() ,goodsInfo.getSupplierId(),
                    YesOrNoEnum.NO.getValue(), 0, YesOrNoEnum.NO.getValue(), goodsInfo.getGoodsSpec(), goodsInfo.getGoodsNo());
            // 锁定库存
//            goodsInfo.setTotalStock(goodsInfo.getTotalStock() - g.getNum());
//            goods.add(goodsInfo);
            list.add(o);
            for (int i = 0; i < g.getNum(); i++) {
                bladeRedis.lPop(CacheBizConstant.GOODS_STORE + g.getGoodsId());
            }
        }
        orderGrouponGoodsService.saveBatch(list);

        // 更新商品，锁定库存
//        goodsInfoService.updateBatchById(goods);
    }

    /**
     * 释放库存
     * @param order
     */
    @Override
    public void releaseGoodsStock(Order order) {
        List<OrderGrouponGoods> list = orderGrouponGoodsService.lambdaQuery().eq(OrderGrouponGoods::getOrderId, order.getId()).list();
        if (CollUtil.isNotEmpty(list)) {
            List<GoodsInfo> goodsInfos = new ArrayList<>();
            for (OrderGrouponGoods o : list) {
                GoodsInfo goodsInfo = goodsInfoService.get(o.getGoodsId());
                goodsInfo.setTotalStock(goodsInfo.getTotalStock() + o.getGoodsNum());
                goodsInfos.add(goodsInfo);
                Object[] stockList = goodsInfoService.getStockList(o.getGoodsNum());
                bladeRedis.getListOps().leftPushAll(CacheBizConstant.GOODS_STORE + o.getGoodsId(), stockList);
            }
//            goodsInfoService.updateBatchById(goodsInfos);
        }
    }

    @Async
    @Override
    public void paySuccessAfter(Order order) {
        OrderGroupon orderGroupon = orderGrouponService.lambdaQuery().eq(OrderGroupon::getOrderId, order.getId()).one();
        User user = userService.getById(order.getUserId());
        // 记录拼团用户
        GrouponUser grouponUser = new GrouponUser();
        grouponUser.setGrouponId(orderGroupon.getGrouponId());
        grouponUser.setUserId(order.getCreateUserId());
        grouponUser.setUserAvatar(user.getAvatar());
        grouponUserService.save(grouponUser);

        // 发送消息
        messageService.sendMessage(order.getUserId(), "订单付款成功，付款方式[" + PaymentTypeEnum.getNameByValue(order.getPaymentMode()) + "]", order.getOrderNo());
        // 计算收益
        commissionService.commissionCalculation(order);
        // 添加结算账户
        Embers embers = embersService.lambdaQuery().eq(Embers::getBindUserId, order.getUserId())
                .eq(Embers::getState,0).one();
        if (embers != null) {
            UserWeChat one = userWeChatService.lambdaQuery().eq(UserWeChat::getUserId, embers.getShareUserId()).one();
            wxPayService.profitSharingAddReceiver(one.getOpenId());
        }

    }

    public GrouponOrderResponse getGroupOrderData(GroupOrderRequest request) {
        User user1 = userService.getById(AuthUtil.getUserId());
        Assert.notNull(user1, "未查询到用户信息，请重启小程序后再试");
        GrouponOrderResponse response = new GrouponOrderResponse();
        Map<Long, Goods> map = request.getGoods().stream().collect(Collectors.toMap(Goods::getGoodsId, Function.identity()));
        List<Long> goodsIds = request.getGoods().stream().map(Goods::getGoodsId).collect(Collectors.toList());
        Assert.notEmpty(goodsIds, "参数异常");
        List<GrouponGoods> list = grouponGoodsService.lambdaQuery().eq(GrouponGoods::getGrouponId, request.getGrouponId()).in(GrouponGoods::getGoodsId, goodsIds).list();
        Map<Long, GrouponGoods> grouponGoodsMap = list.stream().collect(Collectors.toMap(GrouponGoods::getGoodsId, Function.identity()));
        // 查询商品数据
        List<GoodsInfo> goodsInfos = goodsInfoService.lambdaQuery().in(GoodsInfo::getId, goodsIds).list();
        List<GoodsResponse> goodsResponses = new ArrayList<>();
        for (GoodsInfo g : goodsInfos) {
            GrouponGoods grouponGoods = grouponGoodsMap.get(g.getId());
            GoodsResponse goodsResponse = new GoodsResponse(g.getId(), g.getGoodsName(), g.getGoodsCover(), grouponGoods.getGrouponPrice(), map.get(g.getId()).getNum());
            goodsResponses.add(goodsResponse);
        }
        SelfTake selfTake = selfTakeService.getById(request.getSelfTakeId());
        Assert.notNull(selfTake, "自提点信息不存在");
        SelfTakeVO selfTakeVO = SelfTakeWrapper.build().entityVO(selfTake);
        selfTakeVO.setDistance(DistanceUtils.getDistance(request.getLongitude(), request.getLatitude(), selfTake.getLongitude(), selfTake.getLatitude()));
        User user = userService.lambdaQuery().eq(User::getPhone, selfTake.getContactNumber()).one();
        if (user != null) {
            selfTakeVO.setQrCode(user.getWxQrcode());
        }
        // 查询自提点对接团长
//        User user = userService.getById(request.getOrganizerUserId());
//        Assert.notNull(user, "团长信息不存在");

        response.setGoodsInfos(goodsResponses);
        response.setSelfTake(selfTakeVO);
//        response.setPhone(user.getPhone());
//        response.setUsername(user.getName());
//        response.setQrCode(user.getWxQrcode());

        return response;
    }
}
