package com.qs.mp.web.controller.api.user;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.qs.mp.admin.domain.Marketing;
import com.qs.mp.admin.domain.MarketingAwards;
import com.qs.mp.admin.domain.MarketingAwardsPrize;
import com.qs.mp.admin.domain.MarketingMsg;
import com.qs.mp.admin.domain.vo.MarketingAwardsVO;
import com.qs.mp.admin.service.IMarketingAwardsPrizeService;
import com.qs.mp.admin.service.IMarketingAwardsService;
import com.qs.mp.admin.service.IMarketingMsgService;
import com.qs.mp.admin.service.IMarketingService;
import com.qs.mp.common.core.domain.AjaxResult;
import com.qs.mp.common.core.page.TableDataInfo;
import com.qs.mp.common.core.redis.DistributedLocker;
import com.qs.mp.common.core.redis.RedisCache;
import com.qs.mp.common.enums.MarketingCodeTypeEnum;
import com.qs.mp.common.enums.MarketingStatusEnum;
import com.qs.mp.common.enums.UserTypeEnum;
import com.qs.mp.common.exception.ServiceException;
import com.qs.mp.common.utils.DateUtils;
import com.qs.mp.common.utils.StringUtils;
import com.qs.mp.framework.redis.RedisKey;
import com.qs.mp.framework.redis.RedisLockKey;
import com.qs.mp.framework.security.handle.HostHolder;
import com.qs.mp.framework.service.IWxSubscribeMessage;
import com.qs.mp.system.domain.SysUser;
import com.qs.mp.system.service.ISysUserService;
import com.qs.mp.user.domain.MarketingHitPrize;
import com.qs.mp.user.domain.MarketingUserCode;
import com.qs.mp.user.domain.param.MarketingHelpParam;
import com.qs.mp.user.domain.param.UserMarketingQueryParam;
import com.qs.mp.user.domain.vo.UserMarketingDetailVO;
import com.qs.mp.user.domain.vo.UserMarketingListVO;
import com.qs.mp.user.service.IMarketingHitPrizeService;
import com.qs.mp.user.service.IMarketingUserCodeService;
import com.qs.mp.utils.MarketingUtils;
import com.qs.mp.utils.SecurityUtils;
import com.qs.mp.web.controller.common.BaseApiController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import java.time.LocalDateTime;
import org.aspectj.weaver.loadtime.Aj;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author Cup
 * @date 2022/5/17
 */
@RestController
@RequestMapping("/api/v1/mp/user/marketing")
@Api(tags = "营销活动相关接口")
public class MarketingController extends BaseApiController {
    // 营销活动真实参与人数锁
    public static final String MARKETING_REAL_NUM_LOCK = "MARKETING_REAL_NUM_LOCK:%s";

    @Autowired
    private IMarketingService marketingService;

    @Autowired
    private IMarketingHitPrizeService marketingHitPrizeService;

    @Autowired
    private IMarketingAwardsService marketingAwardsService;

    @Autowired
    private IMarketingAwardsPrizeService marketingAwardsPrizeService;

    @Autowired
    private IMarketingUserCodeService marketingUserCodeService;

    @Autowired
    private HostHolder hostHolder;

    @Autowired
    private DistributedLocker distributedLocker;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private IWxSubscribeMessage wxSubscribeMessage;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IMarketingMsgService marketingMsgService;

    @PostMapping("/generateCode/{marketingId}")
    @ApiOperation("立即获取抽奖码")
    public AjaxResult generateCode(@PathVariable("marketingId") Long marketingId) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        if (Objects.isNull(userId)) {
            return AjaxResult.error("用户未登录");
        }

        Marketing marketing = marketingService.getById(marketingId);
        if (Objects.isNull(marketing)) {
            return AjaxResult.error("活动不存在");
        }
        // 未开启的活动不能获取抽奖码
        if (!MarketingStatusEnum.ON.getValue().equals(marketing.getIsOn())) {
            return AjaxResult.error("活动未开启~");
        }
        Date now = DateUtils.getNowDate();
        // 结束的活动不支持获取抽奖码
        if (marketing.getTriggerStatus() == 1 || marketing.getEndTime().before(now)) {
            return AjaxResult.error("活动已过期~");
        }
        // 未开始的活动不能获取抽奖码
        if (marketing.getStartTime().after(now)) {
            return AjaxResult.error("活动未开始~");
        }

        if (!marketing.getCodeType().equals(MarketingCodeTypeEnum.INSTANT.getValue())) {
            return AjaxResult.error("错误请求");
        }

        String lockKey = RedisLockKey.build(RedisLockKey.MARKETING_JOIN_LOCK, userId);
        // 自动续期,等待3秒
        if (!distributedLocker.tryLock(lockKey, 3, -1, TimeUnit.SECONDS)) {
            return AjaxResult.error("活动太火爆了,请稍后重试!");
        }

        try {
            marketingService.generateCode(marketingId, userId);
        }finally {
            distributedLocker.unlock(lockKey);
        }

        return AjaxResult.success("获取成功");

    }


    @PostMapping("/recent")
    @ApiOperation("获取已开始且最近要开奖的营销活动")
    @ApiResponses(
            @ApiResponse(code = 200, message = "OK", response = UserMarketingListVO.class)
    )
    public AjaxResult getRecentMarketing() {
        Date nowDate = DateUtils.getNowDate();
        LambdaQueryWrapper<Marketing> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Marketing::getIsOn, MarketingStatusEnum.ON.getValue());
        queryWrapper.eq(Marketing::getTriggerStatus, 0);
        queryWrapper.le(Marketing::getStartTime, nowDate);
        queryWrapper.ge(Marketing::getEndTime, nowDate);
        queryWrapper.orderByAsc(Marketing::getEndTime, Marketing::getStartTime);
        List<Marketing> marketingList = marketingService.list(queryWrapper);
        if (CollectionUtils.isNotEmpty(marketingList)) {
            UserMarketingListVO userMarketingListVO = new UserMarketingListVO();
            BeanUtils.copyProperties(marketingList.get(0), userMarketingListVO);
            return success(userMarketingListVO);
        }

        return AjaxResult.success();
    }


    @PostMapping("/userInfo/{inviteCode}")
    @ApiOperation("通过邀请码获取用户信息")
    @ApiResponses(
            @ApiResponse(code = 200, message = "成功", response = SysUser.class)
    )
    public AjaxResult userInfoByInviteCode(@PathVariable("inviteCode") String inviteCode) {
        if (StringUtils.isBlank(inviteCode)) {
            return AjaxResult.error("邀请码不能为空");
        }

        Long userId = MarketingUtils.decodeInviteCode(inviteCode);
        SysUser sysUser = sysUserService.selectUserById(userId);
        if (Objects.isNull(sysUser)) {
            return AjaxResult.error("邀请码无效");
        }
        return AjaxResult.success(sysUser);
    }

    @PostMapping("/help")
    @ApiOperation("活动助力")
    public AjaxResult help(@RequestBody MarketingHelpParam marketingHelpParam) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        if (Objects.isNull(userId)) {
            return AjaxResult.error("用户未登录");
        }

        String inviteCode = marketingHelpParam.getInviteCode();
        if (StringUtils.isBlank(inviteCode)) {
            return AjaxResult.error("邀请码不能为空");
        }

        Marketing marketing = marketingService.getById(marketingHelpParam.getMarketingId());
        if (Objects.isNull(marketing)) {
            return AjaxResult.error("活动不存在");
        }
        // 未开启的活动不能助力
        if (!MarketingStatusEnum.ON.getValue().equals(marketing.getIsOn())) {
            return AjaxResult.error("活动未开启~");
        }
        Date now = DateUtils.getNowDate();
        // 结束的活动不支持助力
        if (marketing.getTriggerStatus() == 1 || marketing.getEndTime().before(now)) {
            return AjaxResult.error("活动已过期~");
        }
        // 未开始的活动不能助力
        if (marketing.getStartTime().after(now)) {
            return AjaxResult.error("活动未开始~");
        }

        // 邀请码解码,被助力人id
        Long helpedUserId = MarketingUtils.decodeInviteCode(inviteCode);
        if (userId.equals(helpedUserId)) {
            return AjaxResult.error("不能助力自己哦");
        }

        String lockKey = RedisLockKey.build(RedisLockKey.MARKETING_JOIN_LOCK, userId);

        // 自动续期,等待3秒
        if (!distributedLocker.tryLock(lockKey, 3, -1, TimeUnit.SECONDS)) {
            return AjaxResult.error("活动太火爆了,请稍后重试!");
        }

        try {
            marketingService.help(marketingHelpParam, userId);
        }finally {
            distributedLocker.unlock(lockKey);
        }

        // 保存助力成功消息记录
        MarketingMsg marketingMsg = new MarketingMsg();
        marketingMsg.setMarketingId(marketing.getId());
        marketingMsg.setContext(marketing.getTitle());
        marketingMsg.setUserId(helpedUserId);
        marketingMsg.setType(3);
        marketingMsgService.save(marketingMsg);

        return AjaxResult.success("助力成功");
    }


    @PostMapping("/inviteCode")
    @ApiOperation(value = "邀请码生成", notes = "邀请码生成")
    public AjaxResult inviteCode() {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        if (Objects.isNull(userId)) {
            return AjaxResult.error("用户未登录");
        }
        return AjaxResult.success("邀请码生成成功",MarketingUtils.generateInviteCode(userId));
    }

    @PostMapping("/list")
    @ApiOperation("获取营销活动列表")
    @ApiResponses(
            @ApiResponse(code = 200, message = "成功", response = UserMarketingListVO.class)
    )
    public TableDataInfo list(@Validated @RequestBody UserMarketingQueryParam userMarketingQueryParam) {
        // 获取用户 id
        Long userId = 0L;

        if (hostHolder.getUser() != null) {
            userId = hostHolder.getUser().getUserId();
        }

        startPage();
        LambdaQueryWrapper<Marketing> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Marketing::getIsOn, MarketingStatusEnum.ON.getValue());
        queryWrapper.eq(Marketing::getTriggerStatus, userMarketingQueryParam.getTriggerStatus());
        if (userMarketingQueryParam.getTriggerStatus() == 0) {
            // 已开启的列表
            Date now = DateUtils.getNowDate();
            // 开始时间小于当前时间的
            queryWrapper.le(Marketing::getStartTime, now);
            // 结束时间大于当前时间的
            queryWrapper.gt(Marketing::getEndTime, now);
            queryWrapper.orderByAsc(Marketing::getEndTime, Marketing::getStartTime);
        }else if(userMarketingQueryParam.getTriggerStatus() == 1) {
            // 过滤30天之前的
            LocalDateTime localDateTime = LocalDateTimeUtil.now().minusDays(30);
            queryWrapper.ge(Marketing::getEndTime, localDateTime);

            // 开奖的排序
            queryWrapper.orderByDesc(Marketing::getEndTime);
        }
        List<UserMarketingListVO> userMarketingListVOList = new ArrayList<>();
        List<Marketing> list = marketingService.list(queryWrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            Long finalUserId = userId;
            userMarketingListVOList = list.stream().map(marketing -> {
                UserMarketingListVO userMarketingListVO = new UserMarketingListVO();
                BeanUtils.copyProperties(marketing, userMarketingListVO);
                if (userMarketingQueryParam.getTriggerStatus() == 1) {
                    int count = marketingHitPrizeService.count(new LambdaQueryWrapper<MarketingHitPrize>()
                            .eq(MarketingHitPrize::getMarketingId, marketing.getId())
                            .eq(MarketingHitPrize::getUserId, finalUserId));
                    userMarketingListVO.setIsHit(count);
                } else {
                    String fakeNumKey = RedisKey.build(RedisKey.MARKETING_FAKE_NUM, marketing.getId());
                    Integer fakeNum = redisCache.getCacheObject(fakeNumKey);
                    if (fakeNum == null) {
                        int realNum = marketingUserCodeService.countRealUserNumByMarketingId(marketing.getId());
                        fakeNum = realNum * 2;
                        redisCache.setCacheObject(fakeNumKey, fakeNum, 30, TimeUnit.HOURS);
                    }
                    userMarketingListVO.setFakeNum(fakeNum);
                }
                return userMarketingListVO;
            }).collect(Collectors.toList());
        }
        TableDataInfo dataTable = getDataTable(list);
        dataTable.setRows(userMarketingListVOList);
        return dataTable;
    }

    @PostMapping("/detail/{id}")
    @ApiOperation("活动详情")
    @ApiResponses(
            @ApiResponse(code = 200, message = "成功", response = UserMarketingDetailVO.class)
    )
    public AjaxResult detail(@PathVariable("id") Long id) {
        // 获取用户 id
        Long userId = 0L;

        if (hostHolder.getUser() != null) {
            userId = hostHolder.getUser().getUserId();
        }

        Marketing marketing = marketingService.getById(id);
        if (Objects.isNull(marketing)) {
            return AjaxResult.error("活动不存在");
        }

        UserMarketingDetailVO userMarketingDetailVO = new UserMarketingDetailVO();
        BeanUtils.copyProperties(marketing, userMarketingDetailVO);

        String fakeNumKey = RedisKey.build(RedisKey.MARKETING_FAKE_NUM, id);
        Integer fakeNum = redisCache.getCacheObject(fakeNumKey);
        if (fakeNum == null) {
            int realNum = marketingUserCodeService.countRealUserNumByMarketingId(id);
            fakeNum = realNum * 2;
            redisCache.setCacheObject(fakeNumKey, fakeNum, 30, TimeUnit.HOURS);
        }

        userMarketingDetailVO.setFakeNum(fakeNum);

        List<MarketingAwards> awardsList = marketingAwardsService.list(new LambdaQueryWrapper<MarketingAwards>().eq(MarketingAwards::getMarketingId, id));
        if (CollectionUtils.isNotEmpty(awardsList)) {
            List<MarketingAwardsVO> list = awardsList.stream().map(marketingAwards -> {
                MarketingAwardsVO marketingAwardsVO = new MarketingAwardsVO();
                BeanUtils.copyProperties(marketingAwards, marketingAwardsVO);

                // 获取奖品信息
                List<MarketingAwardsPrize> prizeList = marketingAwardsPrizeService.list(new LambdaQueryWrapper<MarketingAwardsPrize>()
                        .eq(MarketingAwardsPrize::getMarketingId, id)
                        .eq(MarketingAwardsPrize::getAwardsId, marketingAwards.getId()));
                marketingAwardsVO.setPrizeList(prizeList);
                return marketingAwardsVO;
            }).collect(Collectors.toList());

            userMarketingDetailVO.setAwardsList(list);
        }

        // 设置抽奖码列表
        List<MarketingUserCode> codeList = marketingUserCodeService.list(new LambdaQueryWrapper<MarketingUserCode>()
                .select(MarketingUserCode::getCode)
                .eq(MarketingUserCode::getMarketingId, id)
                .eq(MarketingUserCode::getUserId, userId));

        if (CollectionUtils.isNotEmpty(codeList)) {
            userMarketingDetailVO.setCodeList(codeList.stream().map(MarketingUserCode::getCode).collect(Collectors.toList()));
        }

        return AjaxResult.success(userMarketingDetailVO);
    }



}
