package com.qs.mp.framework.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.qs.mp.admin.domain.*;
import com.qs.mp.admin.service.*;
import com.qs.mp.channel.domain.ChannelOrder;
import com.qs.mp.channel.service.IChannelOrderService;
import com.qs.mp.channel.service.IChannelUserRelService;
import com.qs.mp.common.enums.*;
import com.qs.mp.common.exception.ServiceException;
import com.qs.mp.common.utils.DateUtils;
import com.qs.mp.common.utils.LogUtil;
import com.qs.mp.framework.domain.AsyncTask;
import com.qs.mp.framework.mapper.AsyncTaskMapper;
import com.qs.mp.framework.service.IAsyncTaskService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qs.mp.system.domain.SysUser;
import com.qs.mp.system.service.ISysUserService;
import com.qs.mp.user.domain.UserDeliverOrder;
import com.qs.mp.user.domain.UserDeliverOrderItem;
import com.qs.mp.user.domain.UserDeliverOrderItemCard;
import com.qs.mp.user.domain.UserTicketOrder;
import com.qs.mp.user.domain.UserTicketOrderItem;
import com.qs.mp.user.service.IUserDeliverOrderItemCardService;
import com.qs.mp.user.service.IUserDeliverOrderItemService;
import com.qs.mp.user.service.IUserDeliverOrderService;
import com.qs.mp.user.service.IUserHitPrizeService;
import com.qs.mp.user.service.IUserPrizeStorageService;
import com.qs.mp.user.service.IUserTicketOrderItemService;
import com.qs.mp.user.service.IUserTicketOrderService;
import java.util.ArrayList;
import java.util.Date;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author quanshu
 * @since 2022-06-07
 */
@Service
public class AsyncTaskServiceImpl extends ServiceImpl<AsyncTaskMapper, AsyncTask> implements IAsyncTaskService {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());

    @Autowired
    private IChannelOrderService channelOrderService;

    @Autowired
    private IUserTicketOrderService userTicketService;;

    @Autowired
    private IUserTicketOrderService userTicketOrderService;

    @Autowired
    private ITicketBoxService ticketBoxService;

    @Autowired
    private IUserTicketOrderItemService userTicketOrderItemService;

    @Autowired
    private ITicketService ticketService;

    @Autowired
    private ITicketPackageService ticketPackageService;

    @Autowired
    private IChannelUserRelService channelUserRelService;


    @Autowired
    private IUserDeliverOrderService userDeliverOrderService;

    @Autowired
    private IUserDeliverOrderItemService userDeliverOrderItemService;

    @Autowired
    private IGoodsCardService goodsCardService;

    @Autowired
    private IUserDeliverOrderItemCardService userDeliverOrderItemCardService;

    @Autowired
    private ITicketBoxGoodsService ticketBoxGoodsService;

    @Autowired
    private ICouponService couponService;

    @Autowired
    private ICouponPkgService couponPkgService;

    @Autowired
    private IGoodsService goodsService;

    @Autowired
    private IUserPrizeStorageService userPrizeStorageService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private ICdKeyGroupService  cdKeyGroupService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insertAsyncTask(AsyncTaskTypeEnum taskType, String bizId) {
        AsyncTask asyncTask = new AsyncTask();
        asyncTask.setType(taskType.getValue());
        asyncTask.setBizId(bizId);
        return this.save(asyncTask);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void channelConfirmReceipt(AsyncTask asyncTask) {
        // 获取供应商订单编号
        String orderId = asyncTask.getBizId();

        // 查询订单
        ChannelOrder channelOrder = channelOrderService.getById(orderId);
        if (Objects.isNull(channelOrder)) {
            throw new ServiceException("经销商订单不存在,OrderId:" + orderId);
        }

        if (ChannelOrderTypeEnum.RETAIL.equals(channelOrder.getType())) {
            return;
        }

        // 分佣
        userTicketService.commToChannel(orderId, ChannelCommissionResourceEnum.CHANNEL.getValue());
    }

    @Override
    public void ticketPay(AsyncTask asyncTask) {
        String orderId = asyncTask.getBizId();
        UserTicketOrder ticketOrder = userTicketOrderService.getById(orderId);

        TicketBox ticketBox = ticketBoxService.getById(ticketOrder.getBoxId());
        if (ticketBox.getType() == TicketTypeEnum.OFFLINE) {
            // 线下票更新销量，此处不做乐观锁控制，因为不用控制库存
            ticketBoxService.update(
                    new LambdaUpdateWrapper<TicketBox>().set(TicketBox::getSaleQty,
                                    ticketBox.getSaleQty() + 1)
                            .eq(TicketBox::getBoxId, ticketBox.getBoxId()));
        }


        // 更新票组销售数量，此处只做累计，允许并发容错
        List<UserTicketOrderItem> ticketOrderItemList = userTicketOrderItemService.list(new LambdaQueryWrapper<UserTicketOrderItem>()
                .eq(UserTicketOrderItem::getOrderId, orderId));
        for (UserTicketOrderItem orderItem : ticketOrderItemList) {
            Ticket ticket = ticketService.getById(orderItem.getTicketId());
            TicketPackage ticketPackage = ticketPackageService.getById(ticket.getPkgId());
            ticketPackageService.update(new LambdaUpdateWrapper<TicketPackage>()
                    .set(TicketPkgSaleStatusEnum.WAIT_SALE == ticketPackage.getSaleStatus(),
                            TicketPackage::getSaleStatus, TicketPkgSaleStatusEnum.ON_SALE)
                    .set(TicketPkgSaleStatusEnum.ON_SALE == ticketPackage.getSaleStatus()
                                    && ticketPackage.getSaleQty() + 1 >= ticketPackage.getPkgUnit(),
                            TicketPackage::getSaleStatus, TicketPkgSaleStatusEnum.SALE_OUT)
                    .set(TicketPackage::getSaleQty, ticketPackage.getSaleQty() + 1)
                    .eq(TicketPackage::getPkgId, ticketPackage.getPkgId()));
        }

        // 用户关系绑定
        channelUserRelService.bindUser(ticketOrder.getUserId(), ticketOrder.getChannelId());

        if (ticketOrder.getCommStatus() != CommStatusEnum.NO) {
            LogUtil.warn(logger, "收到盲票支付成功任务，订单结佣状态不是未结佣，忽略任务。orderId=" + orderId);
            return;
        }
        userTicketOrderService.commToChannel(orderId, ChannelCommissionResourceEnum.USER.getValue());


    }


    @Override
    public void ticketGenerate(AsyncTask asyncTask) {
        String boxId = asyncTask.getBizId();
        TicketBox ticketBox = ticketBoxService.getById(boxId);
        if (ticketBox.getStatus() != TicketBoxStatusEnum.WAIT ) {
            LogUtil.error(logger, "收到盲票生成任务，票组状态不是待出票，忽略任务。boxId=" + boxId);
            return;
        }
        ticketBoxService.generateTicket(boxId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cardOrderDeliver(AsyncTask asyncTask) {
        String orderId = asyncTask.getBizId();
        LogUtil.info(logger, "收到卡密订单自动发货任务。orderId=" + orderId);
        UserDeliverOrder userDeliverOrder = userDeliverOrderService.getById(orderId);
        // 如果是普通订单或者订单不为待发货则不处理
        if (DeliverOrderTypeEnum.ORDINARY.getValue().equals(userDeliverOrder.getType())
            || !DeliverOrderStatusEnum.NOT_DELIVER.equals(userDeliverOrder.getStatus())) {
            LogUtil.error(logger, "收到卡密订单自动发货任务,订单类型不为卡密订单或者订单状态不为待发货，忽略任务。orderId=" + orderId);
            return;
        }

        // 获取订单详情
        List<UserDeliverOrderItem> userDeliverOrderItemList = userDeliverOrderItemService.list(
            new LambdaQueryWrapper<UserDeliverOrderItem>().eq(UserDeliverOrderItem::getOrderId, orderId));
        if (CollectionUtils.isEmpty(userDeliverOrderItemList)) {
            LogUtil.error(logger, "订单明细为空。orderId=" + orderId);
            throw new ServiceException("订单明细为空");
        }

        // 分配卡密
        List<UserDeliverOrderItemCard> userDeliverOrderItemCardList = new ArrayList<>();
        for (UserDeliverOrderItem userDeliverOrderItem : userDeliverOrderItemList) {
            List<GoodsCard> goodsCardList = goodsCardService.list(new QueryWrapper<GoodsCard>()
                .eq("goods_id", userDeliverOrderItem.getGoodsId())
                .eq("is_use", 0)
                .orderByAsc("rand()")
                .last("limit " + userDeliverOrderItem.getGoodsNum()));
            if (CollectionUtils.isEmpty(goodsCardList) || goodsCardList.size() < userDeliverOrderItem.getGoodsNum()) {
                LogUtil.info(logger,"卡密不足，无法发货。orderId:{0},itemId:{1},goodsId:{2}",userDeliverOrderItem.getOrderId(),
                    userDeliverOrderItem.getItemId(), userDeliverOrderItem.getGoodsId());
                throw new ServiceException("卡密不足，无法发货");
            }

            for (GoodsCard goodsCard : goodsCardList) {
                boolean rtn = goodsCardService.update(new LambdaUpdateWrapper<GoodsCard>()
                    .set(GoodsCard::getIsUse, 1)
                    .eq(GoodsCard::getId, goodsCard.getId())
                    .eq(GoodsCard::getIsUse, 0));
                if (!rtn) {
                    LogUtil.error(logger, "卡密分配失败。orderId={0},itemId={1},goodsId={2}",userDeliverOrderItem.getOrderId(),
                        userDeliverOrderItem.getItemId(), userDeliverOrderItem.getGoodsId());
                    throw new ServiceException("卡密分配并发失败,稍后重试,goodsId=" + userDeliverOrderItem.getGoodsId());
                }
                UserDeliverOrderItemCard userDeliverOrderItemCard = new UserDeliverOrderItemCard();
                userDeliverOrderItemCard.setItemId(userDeliverOrderItem.getItemId());
                userDeliverOrderItemCard.setCardId(goodsCard.getId());
                userDeliverOrderItemCardList.add(userDeliverOrderItemCard);
            }
        }

        boolean rtn = userDeliverOrderItemCardService.saveBatch(userDeliverOrderItemCardList);
        if (!rtn) {
            throw new ServiceException("分配卡密保存失败");
        }

        // 更新订单信息
        boolean res = userDeliverOrderService.update(new LambdaUpdateWrapper<UserDeliverOrder>()
            .set(UserDeliverOrder::getStatus, DeliverOrderStatusEnum.FINISHED)
            .set(UserDeliverOrder::getDeliveryTime, new Date())
            .set(UserDeliverOrder::getConfirmTime, new Date())
            .eq(UserDeliverOrder::getOrderId, orderId)
            .eq(UserDeliverOrder::getStatus, DeliverOrderStatusEnum.NOT_DELIVER)
        );
        if (!res) {
            LogUtil.error(logger, "卡密商品发货更新订单信息失败,orderId: {0}", orderId);
            throw new ServiceException("卡密商品发货更新订单信息失败");
        }

        // 更新订单明细的发货信息
        boolean res1 = userDeliverOrderItemService.update(new LambdaUpdateWrapper<UserDeliverOrderItem>()
            .set(UserDeliverOrderItem::getDeliveryTime, new Date())
            .eq(UserDeliverOrderItem::getOrderId, orderId));
        if(!res1) {
            LogUtil.error(logger,"卡密商品发货更新订单明细发货时间失败,orderId: {0}", orderId);
            throw new ServiceException("卡密商品发货更新订单明细发货时间失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendNewUserCoupon(AsyncTask asyncTask) {
        logger.info("收到发放新人优惠券任务，bizId={}", asyncTask.getBizId());

        SysUser sysUser = sysUserService.selectUserById(Long.valueOf(asyncTask.getBizId()));
        if (sysUser == null) {
            logger.error("收到发放新人优惠券任务,未查到用户信息，bizId={}", asyncTask.getBizId());
            return;
        }
        // 捞取已上架的新人发放优惠券
        List<Coupon> couponList = couponService.list(new LambdaQueryWrapper<Coupon>()
            .eq(Coupon::getType, CouponTypeEnum.TICKET_ORDER)
            .eq(Coupon::getStatus, CouponStatusEnum.PUT_ON)
            .eq(Coupon::getIsNewUserCoupon, 1));
        if (CollectionUtils.isEmpty(couponList)) {
            logger.info("未查到设置的新人优惠券，bizId={}", asyncTask.getBizId());
            return;
        }
        for (Coupon coupon : couponList) {
            couponService.distributeByNewUser(sysUser.getUserId(), coupon.getCouponId());
        }
        logger.info("发放新人优惠券任务结束，bizId={}", asyncTask.getBizId());

    }

    @Override
    public void cdKeyGenerate(AsyncTask asyncTask) {
        String groupId = asyncTask.getBizId();
        CdKeyGroup cdKeyGroup = cdKeyGroupService.getById(groupId);
        if (!CdKeyGroupStatusEnum.WAITING.equals(cdKeyGroup.getStatus())) {
            LogUtil.error(logger, "收到兑换码生成任务，码组状态不是待生成，忽略任务。groupId=" + groupId);
            return;
        }
        cdKeyGroupService.generateCdKey(groupId);
    }


}
