package com.liquidnet.service.kylin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.kylin.constant.KylinRedisConst;
import com.liquidnet.service.kylin.dto.vo.KylinLuckyBagCodeDetailVo;
import com.liquidnet.service.kylin.dto.vo.KylinLuckyBagScopeVo;
import com.liquidnet.service.kylin.dto.vo.KylinLuckyBagVo;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinOrderTicketVo;
import com.liquidnet.service.kylin.dto.vo.returns.OrderDetailsVo;
import com.liquidnet.service.kylin.entity.KylinLuckyBag;
import com.liquidnet.service.kylin.entity.KylinLuckyBagActivity;
import com.liquidnet.service.kylin.entity.KylinRewardCode;
import com.liquidnet.service.kylin.entity.KylinRewardUser;
import com.liquidnet.service.kylin.mapper.KylinRewardCodeMapper;
import com.liquidnet.service.kylin.mapper.KylinRewardUserMapper;
import com.liquidnet.service.kylin.service.IFeishuBotService;
import com.liquidnet.service.kylin.service.IKylinLuckyBagService;
import com.liquidnet.service.kylin.service.IKylinOrderTicketsService;
import com.liquidnet.service.kylin.utils.DataUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class KylinLuckyBagServiceImpl implements IKylinLuckyBagService {

    private static final Logger log = LoggerFactory.getLogger(KylinLuckyBagServiceImpl.class);

    @Autowired
    private DataUtils dataUtils;
    @Autowired
    RedisUtil redisUtil;

    @Autowired
    IKylinOrderTicketsService orderTicketsService;
    @Autowired
    private IFeishuBotService iFeishuBotService;

    @Autowired
    private KylinRewardCodeMapper kylinRewardCodeMapper;
    @Autowired
    private KylinRewardUserMapper kylinRewardUserMapper;


    @Override
    public KylinLuckyBagVo getLuckyBagByOrderId(String orderId) {
        //1. 首先校验用户权限
        OrderDetailsVo vo = orderTicketsService.orderDetails(orderId);
        String uid = CurrentUtil.getCurrentUid();
        if (null == vo) {
            log.error("[getLuckyBagByOrderId] 无权查看该订单, orderId: {}, uid: {}.", orderId, uid);
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("20003");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }
        log.info("[getLuckyBagByOrderId] 获取福袋详情, orderId: {}， uid: {}.", orderId, uid);
        // 判断订单状态
        if (vo.getOrderTicketVo().getStatus() != 1 || vo.getOrderTicketVo().getPayStatus() != 1) {
            log.info("[getLuckyBagByOrderId] 该订单状态不满足权益要求, orderId: {}, uid: {}, status: {}, payStatus: {}.", orderId,
                    uid, vo.getOrderTicketVo().getStatus(), vo.getOrderTicketVo().getPayStatus());
            return KylinLuckyBagVo.ofEmpty();
        }

        // 2. 订单关联的演出ID
        List<KylinLuckyBagVo.LuckyBagActivityVo> activityVos = getLuckyBagActivityVos(vo.getOrderTicketVo().getPerformanceId());

        //3. 再查询满足的权益
        List<KylinLuckyBagVo.LuckyBagVo> luckyBagVos = getLuckyBagVos(vo);

        if (activityVos.isEmpty()) {
            return KylinLuckyBagVo.of(luckyBagVos, null);
        } else {
            return KylinLuckyBagVo.of(luckyBagVos, activityVos.get(0));
        }


    }

    @Override
    public ResponseDto<Boolean> consumeCode(String code, String luckyBagId) {
        LambdaQueryWrapper<KylinRewardUser> queryWrapper = new QueryWrapper<KylinRewardUser>()
                .lambda()
                .eq(KylinRewardUser::getCode, code)
                .eq(KylinRewardUser::getLuckyBagId, luckyBagId);
        KylinRewardUser rewardUser = kylinRewardUserMapper.selectOne(queryWrapper);
        if (rewardUser == null) {
            log.error("code does not exist, code: {}, luckyBagId: {}.", code, luckyBagId);
            return ResponseDto.failure("兑换码无效");
        }
        if (rewardUser.getState().equals(2)) {
            log.info("code be used, code: {}, luckyBagId: {}.", code, luckyBagId);
            return ResponseDto.failure("已被使用");
        }
        rewardUser.setState(2);
        rewardUser.setUpdatedAt(LocalDateTime.now());
        int updateById = kylinRewardUserMapper.updateById(rewardUser);
        log.info("update code result: {}.", updateById);
        return ResponseDto.success(updateById > 0);
    }

    @Override
    public List<KylinLuckyBagScopeVo> getLuckyBagListScope(String mobile, String performanceId) {
        return Collections.emptyList();
    }

    @Override
    public KylinLuckyBagCodeDetailVo getCodeDetail(String code, String luckyBagId) {
        return null;
    }

    /**
     * 获取福袋列表
     *
     * @param vo
     * @return
     */
    private List<KylinLuckyBagVo.LuckyBagVo> getLuckyBagVos(OrderDetailsVo vo) {
        final String performanceId = vo.getOrderTicketVo().getPerformanceId();
        final String orderId = vo.getOrderTicketVo().getOrderTicketsId();
        final String uid = vo.getOrderTicketVo().getUserId();

        List<KylinLuckyBag> luckyBagList = dataUtils.getKylinLuckyBagList();

        if (luckyBagList.isEmpty()) {
            log.info("[getLuckyBagVos] 获取福袋列表为空.");
            return Collections.emptyList();
        }

        // 筛选出 performanceId 为 "abc" 的 KylinLuckyBag 对象
        List<KylinLuckyBag> filteredList = luckyBagList.stream()
                .filter(luckyBag -> performanceId.equals(luckyBag.getPerformanceId()))
                .collect(Collectors.toList());

        List<KylinLuckyBagVo.LuckyBagVo> activityVos = new ArrayList<>(filteredList.size());

        filteredList.forEach(l -> {
            KylinLuckyBagVo.LuckyBagVo luckyBagVo = new KylinLuckyBagVo.LuckyBagVo();
            luckyBagVo.setLuckyBagId(l.getLuckyBagId());
            luckyBagVo.setName(l.getName());
            luckyBagVo.setIntroduction(l.getIntroduction());
            luckyBagVo.setCodeShowType(l.getCodeShowType());

            final String sendTime = l.getSendTime();
            final String nowTime = DateUtil.getNowTime();
            // 判断发放时间
            if (null != sendTime && !sendTime.isEmpty()) {
                if (DateUtil.compareStrDay(nowTime, sendTime) >= 0) { // 当前时间小于发放时间 还未开始呢
                    // 查询数据库获取兑换码
                    List<KylinRewardUser> kylinRewardUserList = dataUtils.getKylinRewardUserList(orderId, uid, l.getLuckyBagId());
                    if (kylinRewardUserList.isEmpty()) {
                        // 根据购买数量来分配兑换码
                        log.info("[getLuckyBagVos] 福袋[{}]已到发放时间，但未给用户分配兑换码, uid: {}, orderId: {}.", l.getName(), uid, orderId);
                        kylinRewardUserList = getRandomRewardCode(vo, l.getLuckyBagId());
                    }
                    Set<String> codeSet = kylinRewardUserList.stream().map(KylinRewardUser::getCode).collect(Collectors.toSet());
                    luckyBagVo.setRewardCodeList(codeSet);
                    luckyBagVo.setStatus(kylinRewardUserList.isEmpty() ? 0 : 1);
                } else {
                    log.info("[getLuckyBagVos] 福袋[{}]未到发放时间.", l.getName());
                    luckyBagVo.setStatus(0);
                    luckyBagVo.setRewardCodeList(Collections.emptySet());
                }
            }
            activityVos.add(luckyBagVo);
        });

        return activityVos;
    }

    /**
     * 分配兑换码
     *
     * @param vo
     * @return
     */
    /**
     * 分配兑换码
     *
     * @param vo
     * @return
     */
    private List<KylinRewardUser> getRandomRewardCode(OrderDetailsVo vo, String luckyBagId) {
        final int limitTotal = vo.getOrderTicketVo().getNumber();
        if (limitTotal <= 0) {
            log.error("[getRandomRewardCode] 用户订单购买数量错误, orderId: {}.", vo.getOrderTicketVo().getOrderTicketsId());
            return Collections.emptyList();
        }

        final String lockKey = KylinRedisConst.LUCKY_BAG_CODE_LOCK + luckyBagId;
        boolean locked = redisUtil.lock(lockKey, 1, 30);
        if (!locked) {
            log.info("[getRandomRewardCode] 未获取到分布式锁.");
            return Collections.emptyList();
        }

        LambdaQueryWrapper<KylinRewardCode> lambdaQueryWrapper = new QueryWrapper<KylinRewardCode>().lambda()
                .eq(KylinRewardCode::getLuckyBagId, luckyBagId)
                .eq(KylinRewardCode::getState, 1)
                .last(true, " limit " + limitTotal);
        //2. 搜索未分配的兑换码
        List<KylinRewardCode> rewardCodes = kylinRewardCodeMapper.selectList(lambdaQueryWrapper);

        if (rewardCodes.size() < limitTotal) {
            log.error("[getRandomRewardCode] 兑换码不足, luckyBagId: {}, need total: {}.", luckyBagId, limitTotal);
            // 报警
            String msg = String.format("福袋ID [%s] 兑换码不足，请及时补充.", luckyBagId);
            iFeishuBotService.sendTextMessage(msg);
            return Collections.emptyList();
        }

        //3. 写入
        final KylinOrderTicketVo orderTicketVo = vo.getOrderTicketVo();
        List<KylinRewardUser> rewardUsers = new ArrayList<>(limitTotal);

        try {
            for (int i = 0; i < rewardCodes.size(); i++) {
                KylinRewardCode lockedRewardCode = rewardCodes.get(i);
                KylinRewardUser rewardUser = buildRewardUser(orderTicketVo.getUserId(),
                        orderTicketVo.getOrderTicketsId(),
                        luckyBagId,
                        orderTicketVo.getEntitiesVoList().get(i).getOrderTicketEntitiesId(),
                        lockedRewardCode.getCode());
                int inserted = kylinRewardUserMapper.insert(rewardUser);
                if (inserted > 0) {
                    // 将兑换码状态更新为已领取
                    int updateResult = kylinRewardCodeMapper.updateByMid(lockedRewardCode.getMid(), 0);
                    if (updateResult <= 0) {
                        log.error("[getRandomRewardCode] 修改兑换码状态失败, luckyBagId: {}, orderId: {}, code: {}.",
                                luckyBagId, orderTicketVo.getOrderTicketsId(), lockedRewardCode.getCode());
                        // 报警
                        String msg = String.format("修改兑换码状态失败：福袋ID: [%s], 用户ID: [%s], 订单ID: [%s], code: [%s]。",
                                luckyBagId, orderTicketVo.getUserId(), orderTicketVo.getOrderTicketsId(), lockedRewardCode.getCode());
                        iFeishuBotService.sendTextMessage(msg);
                    } else {
                        log.info("[getRandomRewardCode] 兑换码分配成功, luckyBagId: {}, orderId: {}, code: {}.",
                                luckyBagId, orderTicketVo.getOrderTicketsId(), lockedRewardCode.getCode());
                        rewardUsers.add(rewardUser);
                    }
                }
            }
            return rewardUsers;
        } catch (Exception e) {
            log.error("error", e);
            // 报警
            iFeishuBotService.sendTextMessage("error: " + e.getMessage());
            return Collections.emptyList();
        } finally {
            redisUtil.uLock(lockKey);
        }
    }

    private KylinRewardUser buildRewardUser(String uid, String orderId, String luckyBagId, String orderTicketEntitiesId, String code) {
        KylinRewardUser user = new KylinRewardUser();
        user.setUid(uid);
        user.setLuckyBagId(luckyBagId);
        user.setOrderId(orderId);
        user.setOrderTicketEntitiesId(orderTicketEntitiesId);
        user.setCode(code);
        user.setState(1);
        user.setCreatedAt(LocalDateTime.now());
        user.setUpdatedAt(LocalDateTime.now());
        return user;
    }

    /**
     * 获取福袋活动列表
     *
     * @param performanceId
     * @return
     */
    private List<KylinLuckyBagVo.LuckyBagActivityVo> getLuckyBagActivityVos(String performanceId) {
        List<KylinLuckyBagVo.LuckyBagActivityVo> activityVos = new ArrayList<>();

        //2. 先查询活动
        List<KylinLuckyBagActivity> luckyBagActivityList = dataUtils.getKylinLuckyBagActivityList();
        luckyBagActivityList.forEach(l -> {
            if (l.getPerformanceId().equals(performanceId)) {
                activityVos.add(new KylinLuckyBagVo.LuckyBagActivityVo(l.getLuckyBagActivityId(),
                        l.getName(),
                        l.getDetail(),
                        l.getTargetUrl()));
            }
        });
        return activityVos;
    }
}
