package com.yonge.cooleshow.biz.dal.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
import com.yonge.cooleshow.auth.api.entity.SysUser;
import com.yonge.cooleshow.biz.dal.dao.ActivityRewardChangeStockDao;
import com.yonge.cooleshow.biz.dal.dao.ActivityRewardDao;
import com.yonge.cooleshow.biz.dal.dto.ActivityRewardDto;
import com.yonge.cooleshow.biz.dal.dto.UserParam;
import com.yonge.cooleshow.biz.dal.dto.search.ActivityRewardChangeStockSearch;
import com.yonge.cooleshow.biz.dal.dto.search.ActivityRewardSearch;
import com.yonge.cooleshow.biz.dal.entity.ActivityPlan;
import com.yonge.cooleshow.biz.dal.entity.ActivityPlanReward;
import com.yonge.cooleshow.biz.dal.entity.ActivityReward;
import com.yonge.cooleshow.biz.dal.entity.ActivityRewardChangeStock;
import com.yonge.cooleshow.biz.dal.entity.CouponInfo;
import com.yonge.cooleshow.biz.dal.entity.PianoRoomChangeRecord;
import com.yonge.cooleshow.biz.dal.enums.*;
import com.yonge.cooleshow.biz.dal.enums.activity.ActivityRankingMethodEnum;
import com.yonge.cooleshow.biz.dal.mapper.CouponInfoMapper;
import com.yonge.cooleshow.biz.dal.service.ActivityPlanRewardService;
import com.yonge.cooleshow.biz.dal.service.ActivityPlanService;
import com.yonge.cooleshow.biz.dal.service.ActivityRewardService;
import com.yonge.cooleshow.biz.dal.service.CouponIssueService;
import com.yonge.cooleshow.biz.dal.service.MemberPriceSettingsService;
import com.yonge.cooleshow.biz.dal.service.PianoRoomChangeRecordService;
import com.yonge.cooleshow.biz.dal.service.SysMessageService;
import com.yonge.cooleshow.biz.dal.vo.ActivityRewardChangeStockVo;
import com.yonge.cooleshow.biz.dal.vo.ActivityRewardVo;
import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
import com.yonge.cooleshow.common.enums.CacheNameEnum;
import com.yonge.cooleshow.common.enums.EStatus;
import com.yonge.cooleshow.common.enums.RewardTypeEnum;
import com.yonge.cooleshow.common.enums.UnitEnum;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.payment.util.DistributedLock;
import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.redisson.api.RedissonClient;
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 javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


@Service
public class ActivityRewardServiceImpl extends ServiceImpl<ActivityRewardDao, ActivityReward> implements ActivityRewardService {
    private final static Logger log = LoggerFactory.getLogger(ActivityRewardServiceImpl.class);

    @Resource
    private ActivityRewardChangeStockDao changeStockDao;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private ActivityPlanService activityPlanService;
    @Autowired
    private SysUserFeignService sysUserFeignService;

    @Autowired
    private SysMessageService sysMessageService;
    @Autowired
    private PianoRoomChangeRecordService pianoRoomChangeRecordService;

    @Autowired
    private CouponInfoMapper couponInfoMapper;

    @Autowired
    private ActivityPlanRewardService activityPlanRewardService;

    @Autowired
    private ActivityRewardService activityRewardService;

    @Autowired
    private MemberPriceSettingsService memberPriceSettingsService;

    @Autowired
    private CouponIssueService couponIssueService;

    @Override
    public ActivityRewardVo detail(Long id) {
        return baseMapper.detail(id);
    }

    @Override
    public ActivityRewardVo detailByActivityId(Long id) {
        return baseMapper.detailByActivityId(id);
    }

    @Override
    public IPage<ActivityRewardVo> selectPage(IPage<ActivityRewardVo> page, ActivityRewardSearch query) {

        List<ActivityRewardVo> rewardInfos = baseMapper.selectPage(page, query);

        if (CollectionUtils.isEmpty(rewardInfos)) {
            // 直接返回请求结果
            return page.setRecords(rewardInfos);
        }

        // 优惠券奖品，查询优惠券名称
        List<Long> couponIds = rewardInfos.stream()
                .filter(x -> RewardTypeEnum.COUPON == x.getRewardType())
                .map(ActivityReward::getCouponId)
                .filter(x -> Optional.ofNullable(x).orElse(0L) > 0)
                .distinct().collect(Collectors.toList());

        // 优惠券名称
        Map<Long, String> couponNameMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(couponIds)) {

            couponNameMap = couponInfoMapper.selectBatchIds(couponIds).stream()
                    .collect(Collectors.toMap(CouponInfo::getId, CouponInfo::getName, (o, n) -> n));
        }

        // 奖品关联活动统计
        List<Long> rewardIds = rewardInfos.stream()
                .map(ActivityReward::getId).distinct().collect(Collectors.toList());

        Map<Long, Integer> collect = getBaseMapper().selectRewardActivityStatInfo(rewardIds).stream()
                .collect(Collectors.toMap(StatGroupWrapper::getId, StatGroupWrapper::getTotal, (o, n) -> n));

        for (ActivityRewardVo item : rewardInfos) {

            item.activityNum(collect.getOrDefault(item.getId(), 0))
                    .setCouponName(couponNameMap.getOrDefault(item.getCouponId(), ""));
        }

        return page.setRecords(rewardInfos);
    }

    @Override
    public List<ActivityRewardVo> selectAll(ActivityRewardSearch query) {
        return baseMapper.selectAll(query);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean submit(ActivityRewardDto activityReward, SysUser user) {
        if (RewardTypeEnum.ACTUAL.equals(activityReward.getRewardType())) {
            activityReward.setNum(1);
            activityReward.setUnit(UnitEnum.PCS);
        } else if (RewardTypeEnum.PIAMO_ROOM.equals(activityReward.getRewardType())) {
            activityReward.setUnit(UnitEnum.MINUTE);
        }

        if (null == activityReward.getId()) {
            activityReward.setCreateBy(user.getId());
            activityReward.setUpdateBy(user.getId());

            baseMapper.insert(activityReward);
        } else {
            activityReward.setStock(null);
            activityReward.setUpdateBy(user.getId());

            // 校验奖品与活动是否存在关联
            int count = activityPlanRewardService.count(Wrappers.<ActivityPlanReward>lambdaQuery()
                    .eq(ActivityPlanReward::getRewardId, activityReward.getId()));
            if (count > 0) {
                throw new BizException("请先解除与活动奖品关联关系");
            }

            baseMapper.updateById(activityReward);
        }
        return true;
    }

    @Override
    public List<ActivityReward> getActivityReward(Long activityPlanId) {
        return baseMapper.getActivityReward(activityPlanId);
    }

    @Override
    public Boolean updateStatus(Long id, Integer status, Long userId) {

        if (EStatus.ENABLE.match(status)) {
            // 更新奖品状态为禁用时，需要判断是否已经关联活动；若存在关联数据，提示用户先解除绑定关系

            int rewardNum = activityPlanRewardService.count(Wrappers.<ActivityPlanReward>lambdaQuery()
                    .eq(ActivityPlanReward::getRewardId, id));

            if (rewardNum > 0) {
                throw new BizException("奖品已被活动关联");
            }
        }

        ActivityReward activityReward = new ActivityReward();
        activityReward.setId(id);
        //更改活动状态
        activityReward.setStatus(status);
        activityReward.setUpdateBy(userId);
        updateById(activityReward);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateStock(ActivityRewardChangeStock changeStock) {
        return DistributedLock.of(redissonClient)
                .runIfLockToFunction(CacheNameEnum.LOCK_REWARD_STOCK.getRedisKey(changeStock.getRewardId())
                        , (param) -> {
                            ActivityReward activityReward = getById(param.getRewardId());
                            Integer stock = (InOrOutEnum.IN.equals(param.getChangeType()))
                                    ? (activityReward.getStock() + param.getStock()) : (activityReward.getStock() - param.getStock());
                            if (stock < 0) {
                                throw new BizException("库存不足");
                            }
                            activityReward.setStock(stock);
                            activityReward.setUpdateBy(param.getCreateBy());
                            baseMapper.updateById(activityReward);

                            changeStockDao.insert(param);
                            return true;
                        }, changeStock, 10l);
    }

    @Override
    public IPage<ActivityRewardChangeStockVo> selectChangeStockPage(IPage<ActivityRewardChangeStockVo> page, ActivityRewardChangeStockSearch query) {
        return page.setRecords(changeStockDao.selectPage(page, query));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> sendReward(Long userId, Long activityId, List<Long> activityRewardIds, Date date) {
        if (userRewarded(userId, activityId)) {
            return new ArrayList<>();
        }
        ActivityPlan activityPlan = activityPlanService.getById(activityId);
        if (activityPlan == null) {
            log.warn("活动不存在");
            return new ArrayList<>();
        }
        if (CollectionUtils.isEmpty(activityRewardIds)) {
            log.warn("奖品不存在");
            return new ArrayList<>();
        }

        // 根据活动关联奖品ID，查询奖品信息
        Collection<ActivityPlanReward> activityRewards = activityPlanRewardService.listByIds(activityRewardIds);

        // 活动奖品信息
        List<Long> rewardIds = activityRewards.stream()
                .map(ActivityPlanReward::getRewardId).distinct().collect(Collectors.toList());

        Map<Long, ActivityReward> rewardInfoMap = activityRewardService.listByIds(rewardIds).stream()
                .collect(Collectors.toMap(ActivityReward::getId, Function.identity(), (o, n) -> n));

        if (MapUtils.isEmpty(rewardInfoMap)) {
            return new ArrayList<>();
        }

        List<Long> activityRewardIdList = new ArrayList<>();
        List<String> rewardNameList = new ArrayList<>();

        ActivityReward activityReward;
        for (ActivityPlanReward item : activityRewards) {

            if (!rewardInfoMap.containsKey(item.getRewardId())) {
                // 没有匹配奖品信息，读取下一行数据
                continue;
            }

            activityReward = rewardInfoMap.get(item.getRewardId());

            // 扣减奖品库存
            int update = activityPlanRewardService.reduceStock(activityId, item.getId());

            // 排除总分排名用户库存限制
            if (ActivityRankingMethodEnum.TOTAL_SCORE != activityPlan.getRankingMethod()
                    && update == 0) {
                continue;
            }

            // 获取推送奖品消息信息
            rewardNameList.add(activityReward.getRewardName());
            // 关联返回数据，更新用户奖品发送状态
            activityRewardIdList.add(item.getId());
        }

        // 发送活动获奖推送
        if (!CollectionUtils.isEmpty(rewardNameList)) {
            String name = String.join(",", rewardNameList);
            sendActivityMessage(userId, activityPlan.getActivityName(),name, activityPlan.getActivityClient());
        }

        return activityRewardIdList;
    }

    @Override
    public void receiveReward(Long userId, Date date, Long activityPlanId, Long activityRewardId) {
        ActivityPlan activityPlan = activityPlanService.getById(activityPlanId);
        ActivityReward activityReward = getById(activityRewardId);
        if (activityPlan == null) {
            throw new BizException("活动不存在");
        }
        if (activityReward == null) {
            throw new BizException("奖品不存在");
        }
        if (activityReward.getRewardType().equals(RewardTypeEnum.PIAMO_ROOM)) {
            // 琴房课时
            PianoRoomChangeRecord pianoRoomChangeRecord = new PianoRoomChangeRecord();
            pianoRoomChangeRecord.setUserId(userId);
            pianoRoomChangeRecord.setInOrOut(InOrOutEnum.IN);
            pianoRoomChangeRecord.setSourceType(SourceTypeEnum.ACTIVITY);
            pianoRoomChangeRecord.setTimes(activityReward.getNum());
            pianoRoomChangeRecord.setBizId(activityPlan.getId().toString());
            pianoRoomChangeRecord.setCreateTime(new Date());
            pianoRoomChangeRecord.setReason(activityPlan.getActivityName());
            pianoRoomChangeRecordService.add(pianoRoomChangeRecord);
        } else if (activityReward.getRewardType().equals(RewardTypeEnum.VIP)) {
            // VIP
            memberPriceSettingsService.activityReward(userId, activityPlan.getActivityClient(), activityReward,
                                                      activityPlan.getId(), activityPlan.getActivityName());
        } else if (activityReward.getRewardType().equals(RewardTypeEnum.COUPON)) {
            // 优惠券
            List<UserParam> list = new ArrayList<>();
            UserParam userParam = new UserParam();
            userParam.setUserId(userId);
            userParam.setClientType(activityPlan.getActivityClient());
            list.add(userParam);
            couponIssueService.saveIssueCoupon(activityReward.getCouponId(), list, null, activityPlan.getActivityName(),
                                                                  SendTypeEnum.ACTIVITY, date);
        }
    }

    @Override
    public Boolean userRewarded(Long userId, Long activityId) {
        return baseMapper.userRewarded(userId, activityId);
    }

    /**
     * 获奖人员发送
     *
     * @param userId             用户id
     * @param activityName       活动名
     * @param activityRewardName 活动奖品名
     */
    private void sendActivityMessage(Long userId, String activityName, String activityRewardName, ClientEnum clientType) {
        SysUser user = sysUserFeignService.queryUserById(userId);
        if (user == null) {
            log.warn("用户未找到");
            return;
        }

        try {
            Map<Long, String> receivers = new HashMap<>();
            receivers.put(userId, user.getPhone());


            String url = sysMessageService.selectConfigUrl(MessageTypeEnum.ACTIVITY_WIN.getCode(),clientType.getCode()
                                                                                        .toLowerCase(Locale.ROOT));
            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.ACTIVITY_WIN, receivers, null,
                    0, url, clientType.getCode(), activityName, activityRewardName);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获奖消息发送失败，{}", e.getMessage());
        }

    }
}