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.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.StringUtil;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.kylin.constant.KylinRedisConst;
import com.liquidnet.service.kylin.constant.LuckyBagStatusEnum;
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.*;
import com.liquidnet.service.kylin.mapper.KylinLuckyBagMapper;
import com.liquidnet.service.kylin.mapper.KylinLuckyBagScopeMapper;
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;
    @Autowired
    private KylinLuckyBagScopeMapper kylinLuckyBagScopeMapper;
    @Autowired
    private KylinLuckyBagMapper kylinLuckyBagMapper;


    @Override
    public ResponseDto<KylinLuckyBagVo> getLuckyBagByOrderId(String orderId) {
        //1. 首先校验用户权限
//        OrderDetailsVo vo = orderTicketsService.orderDetails(orderId);

        final KylinOrderTicketVo orderTicketVo = dataUtils.getOrderTicketVo(orderId);
        final String uid = CurrentUtil.getCurrentUid();
        if (orderTicketVo == null) {
            log.error("[getLuckyBagByOrderId] 未查询到订单, orderId: {}, uid: {}.", orderId, uid);
            return ResponseDto.failure(ErrorMapping.get("20024"));
        }

        if (!orderTicketVo.getUserId().equals(uid)) {
            log.error("[getLuckyBagByOrderId] 无权查看该订单, orderId: {}, uid: {}.", orderId, uid);
            return ResponseDto.failure(ErrorMapping.get("20003"));
        }
        log.info("[getLuckyBagByOrderId] 获取福袋详情, orderId: {}， uid: {}.", orderId, uid);
        // 判断订单状态
        if (isEligibleForWelfare(orderTicketVo)) {
            // 2. 订单关联的演出ID
            List<KylinLuckyBagVo.LuckyBagActivityVo> activityVos = getLuckyBagActivityVos(orderTicketVo.getPerformanceId());

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

            if (activityVos.isEmpty()) {
                return ResponseDto.success(KylinLuckyBagVo.of(luckyBagVos, null));
            } else {
                return ResponseDto.success(KylinLuckyBagVo.of(luckyBagVos, activityVos.get(0)));
            }
        }else {
            log.info("[getLuckyBagByOrderId] 该订单状态不满足权益要求, orderId: {}, uid: {}, status: {}, payStatus: {}.", orderId,
                    uid, orderTicketVo.getStatus(), orderTicketVo.getPayStatus());
            return ResponseDto.success(KylinLuckyBagVo.ofEmpty());
        }
    }


    @Override
    public ResponseDto<List<KylinLuckyBagScopeVo>> getLuckyBagListScope(String mobile) {
        if (StringUtil.isBlank(mobile)) {
            log.info("[getLuckyBagListScope] 手机号为空");
            return ResponseDto.failure(ErrorMapping.get("20004"));
        }
        LambdaQueryWrapper<KylinLuckyBagScope> queryWrapper = new QueryWrapper<KylinLuckyBagScope>()
                .lambda()
                .eq(KylinLuckyBagScope::getMobile, mobile)
                .eq(KylinLuckyBagScope::getState, LuckyBagStatusEnum.AVAILABLE_STATUS_AVAILABLE.getValue());
        List<KylinLuckyBagScope> kylinLuckyBagScopes = kylinLuckyBagScopeMapper.selectList(queryWrapper);
        if (kylinLuckyBagScopes.isEmpty()) {
            log.info("[getLuckyBagListScope] 暂无验码权限, mobile: {}.", mobile);
            return ResponseDto.failure(ErrorMapping.get("20003"));
        }

        // 查询福袋列表
        List<KylinLuckyBag> luckyBagList = dataUtils.getKylinLuckyBagList();
        if (luckyBagList.isEmpty()) {
            log.info("[getLuckyBagListScope] 获取福袋列表为空.");
            return ResponseDto.success();
        }

        // 该手机号可以核验的福袋ID列表
        Set<String> collected = kylinLuckyBagScopes.stream()
                .map(KylinLuckyBagScope::getLuckyBagId)
                .collect(Collectors.toSet());

        return ResponseDto.success(luckyBagList.stream()
                .filter(l -> collected.contains(l.getLuckyBagId()))
                .map(l -> {
                    KylinLuckyBagScopeVo vo = new KylinLuckyBagScopeVo();
                    vo.setLuckyBagId(l.getLuckyBagId());
                    vo.setName(l.getName());
                    vo.setIntroduction(l.getIntroduction());
                    vo.setPerformanceId(l.getPerformanceId());
                    vo.setPerformanceName(l.getPerformanceName());
                    return vo;
                })
                .collect(Collectors.toList()));
    }

    @Override
    public ResponseDto<KylinLuckyBagCodeDetailVo> getCodeDetail(String authMobile, String code, String luckyBagId) {
        if (!checkScopeByMobile(authMobile, luckyBagId)) {
            log.info("暂无验码权限, mobile: {}, luckyBagId: {}.", authMobile, luckyBagId);
            return ResponseDto.failure(ErrorMapping.get("20003"));
        }
        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: {}, luckyBagId: {}.", code, luckyBagId);
            return ResponseDto.failure(ErrorMapping.get("20800"));
        }

        KylinOrderTicketVo orderTicketVo = dataUtils.getOrderTicketVo(rewardUser.getOrderId());
        if (orderTicketVo == null) {
            log.error("订单详情为空, orderId: {}.", rewardUser.getOrderId());
            iFeishuBotService.sendTextMessage("订单不存在, orderId: " + rewardUser.getOrderId());
            return ResponseDto.failure(ErrorMapping.get("20801"));
        }
        return ResponseDto.success(buildCodeDetailVo(rewardUser, orderTicketVo));
    }

    @Override
    public ResponseDto<Boolean> consumeCode(String authMobile, String code, String luckyBagId) {
        if (!checkScopeByMobile(authMobile, luckyBagId)) {
            log.info("暂无验码权限, mobile: {}, luckyBagId: {}.", authMobile, luckyBagId);
            return ResponseDto.failure(ErrorMapping.get("20003"));
        }
        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: {}, luckyBagId: {}.", code, luckyBagId);
            return ResponseDto.failure(ErrorMapping.get("20800"));
        }
        if (LuckyBagStatusEnum.AVAILABLE_STATUS_RECEIVED.getValue().equals(rewardUser.getState())) {
            log.info("兑换码被使用, code: {}, luckyBagId: {}.", code, luckyBagId);
            return ResponseDto.failure(ErrorMapping.get("20802"));
        }
        rewardUser.setState(LuckyBagStatusEnum.AVAILABLE_STATUS_RECEIVED.getValue());
        rewardUser.setComment(authMobile);
        rewardUser.setUpdatedAt(LocalDateTime.now());
        int updateById = kylinRewardUserMapper.updateById(rewardUser);
        log.info("核销兑换码: {}.", updateById > 0);
        return ResponseDto.success(updateById > 0);
    }

    private KylinLuckyBagCodeDetailVo buildCodeDetailVo(KylinRewardUser rewardUser,
                                                        KylinOrderTicketVo orderTicketVo) {
        KylinLuckyBagCodeDetailVo detailVo = new KylinLuckyBagCodeDetailVo();
        detailVo.setLuckyBagId(rewardUser.getLuckyBagId());
        KylinLuckyBag luckyBag = getLuckyBagById(rewardUser.getLuckyBagId());
        if (luckyBag != null) {
            detailVo.setLuckyBagName(luckyBag.getName());
        }
        detailVo.setCode(rewardUser.getCode());
        detailVo.setUseStatus(rewardUser.getState());
        detailVo.setCreatedAt(rewardUser.getCreatedAt());
        detailVo.setUpdatedAt(rewardUser.getUpdatedAt());
        detailVo.setUserInfo(getUserInfo(orderTicketVo));
        detailVo.setOrderInfo(getOrderInfo(orderTicketVo));
        detailVo.setOperator(getOperator(rewardUser.getComment(), rewardUser.getLuckyBagId()));
        return detailVo;
    }


    /**
     * 根据福袋ID获取福袋信息
     *
     * @param luckyBagId
     * @return
     */
    private KylinLuckyBag getLuckyBagById(String luckyBagId) {
        LambdaQueryWrapper<KylinLuckyBag> wrapper = new QueryWrapper<KylinLuckyBag>().lambda()
                .eq(KylinLuckyBag::getLuckyBagId, luckyBagId);
        return kylinLuckyBagMapper.selectOne(wrapper);
    }

    /**
     * 获取用户信息
     *
     * @param orderTicketVo
     * @return
     */
    private KylinLuckyBagCodeDetailVo.UserInfo getUserInfo(KylinOrderTicketVo orderTicketVo) {
        if (orderTicketVo == null) {
            return null;
        }
        KylinLuckyBagCodeDetailVo.UserInfo userInfo = new KylinLuckyBagCodeDetailVo.UserInfo();
        userInfo.setUid(orderTicketVo.getUserId());
        userInfo.setUserName(orderTicketVo.getUserName());
        userInfo.setUserMobile(orderTicketVo.getUserMobile());
        return userInfo;
    }

    /**
     * 获取订单信息
     *
     * @param orderTicketVo
     * @return
     */
    private KylinLuckyBagCodeDetailVo.OrderInfo getOrderInfo(KylinOrderTicketVo orderTicketVo) {
        if (orderTicketVo == null) {
            return null;
        }
        KylinLuckyBagCodeDetailVo.OrderInfo orderInfo = new KylinLuckyBagCodeDetailVo.OrderInfo();
        orderInfo.setOrderId(orderTicketVo.getOrderTicketsId());
        orderInfo.setOrderCode(orderTicketVo.getOrderCode());
        orderInfo.setPerformanceTitle(orderTicketVo.getPerformanceTitle());
        orderInfo.setTicketTitle(orderTicketVo.getTicketTitle());
        orderInfo.setNumber(orderTicketVo.getNumber());
        orderInfo.setRefundNumber(orderTicketVo.getRefundNumber());
        orderInfo.setCreatedAt(orderTicketVo.getCreatedAt());
        orderInfo.setUseStart(orderTicketVo.getUseStart());
        return orderInfo;
    }

    /**
     * 获取核验人信息
     *
     * @return
     */
    private KylinLuckyBagCodeDetailVo.Operator getOperator(String mobile, String luckyBagId) {
        if (StringUtil.isBlank(mobile)) {
            return null;
        }
        LambdaQueryWrapper<KylinLuckyBagScope> queryWrapper = new QueryWrapper<KylinLuckyBagScope>().lambda()
                .eq(KylinLuckyBagScope::getMobile, mobile)
                .eq(KylinLuckyBagScope::getLuckyBagId, luckyBagId);
        KylinLuckyBagScope luckyBagScope = kylinLuckyBagScopeMapper.selectOne(queryWrapper);
        if (luckyBagScope == null) {
            return null;
        }
        return new KylinLuckyBagCodeDetailVo.Operator(luckyBagScope.getMobile(), luckyBagScope.getNickName());
    }

    /**
     * 获取福袋列表
     *
     * @param orderTicketVo
     * @return
     */
    private List<KylinLuckyBagVo.LuckyBagVo> getLuckyBagVos(KylinOrderTicketVo orderTicketVo) {
        final String performanceId = orderTicketVo.getPerformanceId();
        final String orderId = orderTicketVo.getOrderTicketsId();
        final String uid = orderTicketVo.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(orderTicketVo, l.getLuckyBagId());
                    }
                    List<KylinLuckyBagVo.RewardCodeVo> codeVoList = kylinRewardUserList.stream().map(k -> {
                        KylinLuckyBagVo.RewardCodeVo rewardCodeVo = new KylinLuckyBagVo.RewardCodeVo();
                        rewardCodeVo.setUseStatus(k.getState());
                        rewardCodeVo.setCode(k.getCode());
                        return rewardCodeVo;
                    }).collect(Collectors.toList());

                    luckyBagVo.setRewardCodeVoList(codeVoList);
                    luckyBagVo.setStatus(kylinRewardUserList.isEmpty() ?
                            LuckyBagStatusEnum.UNLOCK_STATUS_NOT_UNLOCKED.getValue() : LuckyBagStatusEnum.UNLOCK_STATUS_UNLOCKED.getValue());
                } else {
                    log.info("[getLuckyBagVos] 福袋[{}]未到发放时间.", l.getName());
                    luckyBagVo.setStatus(LuckyBagStatusEnum.UNLOCK_STATUS_NOT_UNLOCKED.getValue());
                    luckyBagVo.setRewardCodeVoList(Collections.emptyList());
                }
            }
            activityVos.add(luckyBagVo);
        });

        return activityVos;
    }


    /**
     * 分配兑换码
     *
     * @param orderTicketVo
     * @return
     */
    private List<KylinRewardUser> getRandomRewardCode(KylinOrderTicketVo orderTicketVo, String luckyBagId) {
        final int limitTotal = orderTicketVo.getNumber() - orderTicketVo.getRefundNumber();
        if (limitTotal <= 0) {
            log.error("[getRandomRewardCode] 用户订单购买数量错误, orderId: {}.", orderTicketVo.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, LuckyBagStatusEnum.AVAILABLE_STATUS_AVAILABLE.getValue())
                .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. 写入
        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(),
                            LuckyBagStatusEnum.AVAILABLE_STATUS_UNAVAILABLE.getValue());
                    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(LuckyBagStatusEnum.AVAILABLE_STATUS_AVAILABLE.getValue());
        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;
    }

    /**
     * 校验手机号是否有权限验码
     *
     * @param mobile
     * @param luckyBagId
     * @return
     */
    private boolean checkScopeByMobile(String mobile, String luckyBagId) {
        if (StringUtil.isBlank(mobile)) {
            log.info("mobile is blank.");
            return false;
        }
        LambdaQueryWrapper<KylinLuckyBagScope> queryWrapper = new QueryWrapper<KylinLuckyBagScope>().lambda()
                .eq(KylinLuckyBagScope::getMobile, mobile)
                .eq(KylinLuckyBagScope::getLuckyBagId, luckyBagId)
                .eq(KylinLuckyBagScope::getState, LuckyBagStatusEnum.AVAILABLE_STATUS_AVAILABLE.getValue());
        KylinLuckyBagScope kylinLuckyBagScope = kylinLuckyBagScopeMapper.selectOne(queryWrapper);
        return kylinLuckyBagScope != null;
    }

    /**
     * 判断是否满足发放福利条件
     *
     * @param orderTicketVo 订单票务信息对象
     * @return 是否满足条件
     */
    private boolean isEligibleForWelfare(KylinOrderTicketVo orderTicketVo) {
        if (orderTicketVo == null) {
            log.info("[isEligibleForWelfare] 订单信息为空.");
            return false;
        }

        Integer status = orderTicketVo.getStatus();
        Integer payStatus = orderTicketVo.getPayStatus();
        Integer number = orderTicketVo.getNumber();
        Integer refundNumber = orderTicketVo.getRefundNumber();
        log.info("[isEligibleForWelfare] 订单信息, status: {}, payStatus: {}, number: {}, refundNumber: {}.",
                status, payStatus, number, refundNumber);

        return (status != null && (status.equals(1) || status.equals(6))) &&
                (payStatus != null && payStatus.equals(1)) &&
                (number != null && refundNumber != null && (number - refundNumber) > 0);
    }
}
