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

import com.alibaba.fastjson.JSONObject;
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.qs.mp.admin.domain.*;
import com.qs.mp.admin.domain.vo.TicketListVO;
import com.qs.mp.admin.service.*;
import com.qs.mp.channel.domain.Channel;
import com.qs.mp.channel.service.IChannelService;
import com.qs.mp.common.annotation.Log;
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.enums.*;
import com.qs.mp.common.utils.DateUtils;
import com.qs.mp.common.utils.StringUtils;
import com.qs.mp.core.domain.LoginUser;
import com.qs.mp.framework.redis.RedisLockKey;
import com.qs.mp.system.domain.SysUser;
import com.qs.mp.system.service.ISysUserService;
import com.qs.mp.user.domain.*;
import com.qs.mp.user.domain.dto.CoinTransferParamDTO;
import com.qs.mp.user.domain.param.*;
import com.qs.mp.user.domain.vo.UserCouponVO;
import com.qs.mp.user.domain.vo.UserExchangeCdKeyVO;
import com.qs.mp.user.domain.vo.UserPrizeStorageVO;
import com.qs.mp.user.service.*;
import com.qs.mp.utils.SecurityUtils;
import com.qs.mp.web.controller.common.BaseApiController;
import io.swagger.annotations.*;

import java.util.*;

import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import ma.glasnost.orika.MapperFacade;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/api/v1/mp/user/mine")
@Api(tags = "我的接口")
@AllArgsConstructor
public class UserMineController extends BaseApiController {


    @Autowired
    private IUserTicketOrderItemService userTicketOrderItemService;

    @Autowired
    private IUserPrizeStorageService userPrizeStorageService;

    @Autowired
    private IUserCoinService userCoinService;

    @Autowired
    private IUserCouponService userCouponService;

    @Autowired
    private IUserCoinLogService userCoinLogService;

    @Autowired
    private MapperFacade mapperFacade;

    @Autowired
    private IGoodsService goodsService;

    @Autowired
    private ICouponChannelService couponChannelService;

    @Autowired
    private ICouponService couponService;

    @Autowired
    private IChannelService channelService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private ICdKeyService cdKeyService;

    @Autowired
    private ICdKeyExchangeService exchangeService;

    @Autowired
    private ICdKeyGroupService cdKeyGroupService;

    @Autowired
    private IUserRedPkgService redPkgService;

    @Autowired
    private DistributedLocker distributedLocker;

    @Log(title = "昵称和头像修改", businessType = BusinessType.UPDATE)
    @PostMapping("/updateUserInfo")
    public AjaxResult updateUserInfo(@RequestBody SysUser user) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        String avatar = user.getAvatar();
        String nickName = user.getNickName();

        if (userId == null || userId <= 0L) {
            return AjaxResult.error("用户ID不正确");
        }
        SysUser sysUser = userService.selectUserById(userId);
        if (sysUser == null) {
            return AjaxResult.error("用户不存在");
        }

        if (StringUtils.isBlank(nickName)) {
            return AjaxResult.error("用户昵称不能为空");
        }

        if (StringUtils.isBlank(avatar)) {
            return AjaxResult.error("用户头像不能为空");
        }

        user.setUserId(userId);
        // 更新用户昵称和头像
        userService.updateUserProfile(user);

        return AjaxResult.success();
    }


    /**
     * 我的票包
     */
    @PostMapping("/ticket/list")
    @ApiOperation(value = "我的盲票列表", notes = "获取我的盲票列表")
    @ApiResponses(
        @ApiResponse(code = 200, message = "成功", response = TicketListVO.class)
    )
    public TableDataInfo listTicket(@RequestBody Ticket param) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        startPage();
        List<TicketListVO> ticketListVOS = userTicketOrderItemService.listMyTicketVO(userId,
            param.getStatus());

        // 已兑奖的盲豆奖品需要拼接数量
        if (TicketStatusEnum.CASHED.equals(param.getStatus())) {
            for (TicketListVO ticketListVO : ticketListVOS) {
                if (StringUtils.isBlank(ticketListVO.getPrizeInfo())) {
                    continue;
                }
                // 如果为盲豆需要拼接数量
                if (TicketPrizeTypeEnum.COIN.getValue().equals(ticketListVO.getPrizeType())) {
                    ticketListVO.setPrizeInfo(ticketListVO.getPrizeInfo() + ticketListVO.getValue() + "个");
                }
            }
        }
        return getDataTable(ticketListVOS);
    }

    /**
     * 我的优惠券
     */
    @PostMapping("/coupon/list")
    @ApiOperation(value = "我的优惠券列表", notes = "获取我的优惠券列表")
    @ApiResponses(
        @ApiResponse(code = 200, message = "成功", response = UserCouponVO.class)
    )
    public TableDataInfo listCoupon(@RequestBody UserCoupon param) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        startPage();
        List<UserCouponVO> userCouponVOList = userCouponService.listCoupon(userId, param.getStatus());
        return getDataTable(userCouponVOList);
    }

    /**
     * 我的红包
     */
    @PostMapping("/red/pkg/list")
    @ApiOperation("我的红包")
    @ApiResponses(
            @ApiResponse(code = 200, message = "成功", response = UserRedPkg.class)
    )
    public TableDataInfo redPkgList(@RequestBody UserRedPkg redPkg) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        startPage();
        List<UserRedPkg> redPkgList = redPkgService.list(new QueryWrapper<UserRedPkg>().eq("user_id", userId)
                .eq("status", redPkg.getStatus())
                .orderByDesc(UserRedPkgStatusEnum.UN_DRAW.equals(redPkg.getStatus()), "created_time")
                .orderByDesc(UserRedPkgStatusEnum.DRAW.equals(redPkg.getStatus()), "draw_time"));
        return getDataTable(redPkgList);
    }

    /**
     * 红包领取
     */
    @PostMapping("red/pkg/draw")
    @ApiOperation("红包领取")
    public AjaxResult redPkgDraw(@RequestBody RedPkgDrawParam param) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Long userId = loginUser.getUserId();
        SysUser sysUser = userService.selectUserById(userId);
        if (sysUser == null) {
            return AjaxResult.error("用户不存在");
        }
        if (StringUtils.isNotEmpty(sysUser.getMsdqOpenId())) {
            param.setOpenId(sysUser.getMsdqOpenId());
        }
        if (param.getOpenId() == null) {
            return AjaxResult.error("您未微信授权登录，无法提现，请重新微信授权登录");
        }
        String lockKey = RedisLockKey.build(RedisLockKey.USER_RED_PKG_DRAW_LOCK, userId);
        if (!distributedLocker.tryLock(lockKey)) {
            return AjaxResult.error("红包提现太频繁，请稍后再操作");
        }
        boolean rst = false;
        try {
             rst = redPkgService.draw(param);
        }finally {
            distributedLocker.unlock(lockKey);
        }
        if (rst) {
            return AjaxResult.success("红包领取成功，请查看微信钱包零钱余额");
        }
        return AjaxResult.error("系统繁忙，请联系客服处理");
    }

    /**
     * 优惠券详情
     */
    @PostMapping("/coupon/detail")
    @ApiOperation(value = "优惠券详情", notes = "获取我的优惠券详情")
    @ApiResponses(
        @ApiResponse(code = 200, message = "成功", response = UserCouponVO.class)
    )
    public AjaxResult getCouponInfo(@RequestBody UserCoupon param) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        List<UserCouponVO> userCouponVOList = userCouponService.listUserCouponVO(new QueryWrapper<UserCoupon>()
            .eq("t1.id", param.getId())
            .eq("t1.user_id", userId));
        if (!CollectionUtils.isEmpty(userCouponVOList)) {
            UserCouponVO userCouponVO = userCouponVOList.get(0);

            Coupon coupon = couponService.getById(userCouponVO.getCouponId());
            if (CouponTypeEnum.SITE_CONSUME.equals(coupon.getType())) {
                if (CouponUseAreaEnum.COMMON.equals(coupon.getUseArea())) {
                    // 所有门店
                    int channelTotal = channelService.count(new LambdaQueryWrapper<Channel>().eq(Channel::getLevel, 0));
                    userCouponVO.setChannelTotal(channelTotal);

                }else if (CouponUseAreaEnum.PRE_SCOPE.equals(coupon.getUseArea())) {
                    // 指定门店
                    int channelTotal = couponChannelService.count(new LambdaQueryWrapper<CouponChannel>()
                        .eq(CouponChannel::getCouponId, userCouponVO.getCouponId()));
                    userCouponVO.setChannelTotal(channelTotal);
                }
            }
            return AjaxResult.success(userCouponVO);
        }
        return AjaxResult.error("优惠券不存在");
    }


    @PostMapping("/coupon/channel/list")
    @ApiOperation("优惠券关联门店列表")
    @ApiResponses(
        @ApiResponse(code = 200, message = "成功", response = Channel.class)
    )
    public TableDataInfo listCouponChannel(@RequestBody CouponChannelQueryParam param) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        if (param.getCouponId() == null) {
            return getErrorDataTable("优惠券id不能为空");
        }

        Coupon coupon = couponService.getById(param.getCouponId());
        if (coupon == null) {
            return getErrorDataTable("优惠券信息不存在");
        }

        List<Channel> channelList = new ArrayList<>();
        LambdaQueryWrapper<Channel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(null != param.getProvinceId(), Channel::getProvinceId, param.getProvinceId());
        queryWrapper.eq(null != param.getCityId(), Channel::getCityId, param.getCityId());
        queryWrapper.eq(null != param.getAreaId(), Channel::getAreaId, param.getAreaId());

        if (CouponUseAreaEnum.PRE_SCOPE.equals(coupon.getUseArea())) {
            List<CouponChannel> couponChannelList = couponChannelService.list(
                new LambdaQueryWrapper<CouponChannel>().eq(CouponChannel::getCouponId, coupon.getCouponId()));
            if (CollectionUtils.isEmpty(couponChannelList)) {
                return getDataTable(channelList);
            }
            List<Long> channelIds = couponChannelList.stream().map(CouponChannel::getChannelId)
                .collect(Collectors.toList());
            queryWrapper.in(Channel::getChannelId, channelIds);
        }
        startPage();
        channelList = channelService.list(queryWrapper);
        return getDataTable(channelList);
    }


    /**
     * 我的盲豆
     */
    @PostMapping("/coin/log/list")
    @ApiOperation(value = "我的盲豆记录", notes = "获取我的盲豆记录")
    @ApiResponses(
        @ApiResponse(code = 200, message = "成功", response = UserCoinLog.class)
    )
    public TableDataInfo listCoinLog(@RequestBody JSONObject param) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        startPage();
        List<UserCoinLog> userCoinLogList = userCoinLogService.list(
            new LambdaQueryWrapper<UserCoinLog>()
                .eq(UserCoinLog::getUserId, userId).orderByDesc(UserCoinLog::getBizTime));
        return getDataTable(userCoinLogList);
    }

    /**
     * 根据手机号查询用户昵称
     */
    @PostMapping("/sysUser/mobile/{mobile}")
    @ApiOperation(value = "根据手机号查询用户信息")
    @ApiImplicitParams(
            @ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String", paramType = "path")
    )
    @ApiResponses(
            @ApiResponse(code = 200, message = "成功", response = SysUser.class)
    )
    public AjaxResult sysUserInfoByMobile(@PathVariable("mobile") String mobile){
        if (StringUtils.isBlank(mobile)) {
            return AjaxResult.success();
        }
        SysUser user = userService.selectUserByPhoneNumber(mobile);
        if (Objects.isNull(user)) {
            return AjaxResult.success("该用户不存在");
        }
        if (Objects.nonNull(user.getChannelOpenId()) && Objects.nonNull(user.getMsdqOpenId())) {
            // 既是B端用户、又是C端用户，可以查到
        } else if (Objects.nonNull(user.getChannelOpenId())) {
            // 只是B端用户
            return AjaxResult.success("该用户不存在");
        }
        SysUser userVO = new SysUser();
        userVO.setNickName(user.getNickName());
        return AjaxResult.success(userVO);
    }

    /**
     * 盲豆转让
     */
    @PostMapping("/coin/transfer/save")
    @ApiOperation(value = "盲豆转赠")
    public AjaxResult transfer(@RequestBody CoinTransferParam coinTransferParam) {
        // 自己为转让人
        Long fromUserId = SecurityUtils.getUserId();
        if (fromUserId == null) {
            return AjaxResult.error("非法调用");
        }
        if (StringUtils.isBlank(coinTransferParam.getPhone())
                || Objects.isNull(coinTransferParam.getTransferCoin())) {
            return AjaxResult.error("转赠参数不能为空");
        }

        // 校验受赠人信息
        SysUser toUser = userService.selectUserByPhoneNumber(coinTransferParam.getPhone());
        if (Objects.isNull(toUser)) {
            return AjaxResult.error("未查询到受赠用户");
        }
        if (fromUserId.equals(toUser.getUserId())) {
            return AjaxResult.error("不能转赠给自己");
        }

        SysUser fromUser = userService.selectUserById(fromUserId);
        CoinTransferParamDTO coinTransferParamDTO = new CoinTransferParamDTO();
        coinTransferParamDTO.setFromUserId(fromUserId);
        coinTransferParamDTO.setToUserId(toUser.getUserId());
        coinTransferParamDTO.setToPhone(coinTransferParam.getPhone());
        coinTransferParamDTO.setFromPhone(fromUser.getPhonenumber());
        coinTransferParamDTO.setRealTransferCoin(coinTransferParam.getTransferCoin() - 10);
        coinTransferParamDTO.setDeductTransferCoin(10);

        // 转赠盲豆
        boolean flag = userCoinService.transfer(coinTransferParamDTO);

        return AjaxResult.success(flag);
    }
    /**
     * 我的实物奖品库
     */
    @PostMapping("/prize/list")
    @ApiOperation(value = "我的实物奖品库", notes = "获取我的实物奖品库")
    @ApiResponses(
        @ApiResponse(code = 200, message = "成功", response = UserPrizeStorageVO.class)
    )
    public TableDataInfo listPrize(@RequestBody JSONObject param) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        startPage();
        QueryWrapper<UserPrizeStorage> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("t1.user_id", userId);
        queryWrapper.eq("t1.status", PrizeStorageStatusEnum.NOT_DISTRIBUTED);
        queryWrapper.orderByDesc("t1.created_time");
        List<UserPrizeStorageVO> userPrizeStorageVOList = userPrizeStorageService.listByQueryWrapper(queryWrapper);
        return getDataTable(userPrizeStorageVOList);
    }


    @PostMapping("/prize/saveSku")
    @ApiOperation("设置实物奖品的SKU")
    @ApiResponses(
        @ApiResponse(code = 200, message = "success")
    )
    public AjaxResult saveSku(@Validated @RequestBody UserPrizeStorageUpdateParam userPrizeStorageUpdateParam) {
        UserPrizeStorage userPrizeStorage = userPrizeStorageService.getById(userPrizeStorageUpdateParam.getStorageId());
        if (userPrizeStorage == null) {
            return AjaxResult.error("奖品存储ID不正确");
        }

        if (PrizeStorageInTypeEnum.COIN_EXCHANGE.equals(userPrizeStorage.getInType())) {
            return AjaxResult.error("当前来源不支持选择规格");
        }

        if (userPrizeStorage.getSkuId() != null) {
            return AjaxResult.error("非法调用,已存在规格");
        }

        // 保存商品的sku信息
        boolean rtn = userPrizeStorageService.update(new LambdaUpdateWrapper<UserPrizeStorage>()
            .set(UserPrizeStorage::getSkuId, userPrizeStorageUpdateParam.getSkuId())
            .set(UserPrizeStorage::getProperties, userPrizeStorageUpdateParam.getProperties())
            .eq(UserPrizeStorage::getStorageId, userPrizeStorageUpdateParam.getStorageId()));
        if (!rtn) {
            return AjaxResult.error("保存规格失败,请重试");
        }

        return AjaxResult.success();
    }


    /**
     * 我的
     */
    @PostMapping("/init")
    @ApiOperation(value = "查看我的", notes = "查看我的")
    public AjaxResult getInfo(@RequestBody JSONObject param) {
        Long userId = SecurityUtils.getLoginUser().getUserId();
        Map<String, Object> storageMap = userPrizeStorageService.getMap(
            new QueryWrapper<UserPrizeStorage>()
                .select("count(IFNULL(goods_num,0)) as total")
                .eq("user_id", userId).eq("status", PrizeStorageStatusEnum.NOT_DISTRIBUTED));
        int couponCnt = userCouponService.count(new LambdaQueryWrapper<UserCoupon>()
            .eq(UserCoupon::getUserId, userId)
            .eq(UserCoupon::getStatus, UserCouponStatusEnum.UNUSED)
            .le(UserCoupon::getValidStart, DateUtils.getToday())
            .ge(UserCoupon::getValidEnd, DateUtils.getToday()));
        JSONObject result = new JSONObject();
        result.put("prizeNum",
            Integer.valueOf(String.valueOf(null != storageMap ? storageMap.get("total") : 0)) + couponCnt);

        int ticketNum = userTicketOrderItemService.countMyTicket(userId, null);
        result.put("ticketNum", ticketNum);

        UserCoin userCoin = userCoinService.getById(userId);
        result.put("coinNum", null != userCoin ? userCoin.getCoin() : 0);
        return AjaxResult.success(result);
    }

    @ApiOperation(value = "兑换码兑换")
    @PostMapping("/cdKey/exchange")
    @ApiResponses(
            @ApiResponse(code = 200, message = "成功", response = UserExchangeCdKeyVO.class)
    )
    public AjaxResult ticketExchange(@RequestBody CdKeyExchangeParam param) {
        CdKey cdKey = cdKeyService.getOne(new QueryWrapper<CdKey>().eq("cd_key", param.getCdKey()));
        if (cdKey == null) {
            return AjaxResult.error("兑换码不存在");
        }
        if (cdKey.getStatus() == 1) {
            return AjaxResult.error("兑换码已被兑换");
        }
        // 判断兑换码是否失效
        CdKeyGroup cdKeyGroup = cdKeyGroupService.getById(cdKey.getGroupId());
        if (CdKeyGroupStatusEnum.ACTIVATED == cdKeyGroup.getStatus()) {
            int validityPeriod = ValidityPeriodEnum.getByValue(cdKeyGroup.getValidityPeriod().getValue());
            if (validityPeriod == 3 && DateUtils.diffMonth(cdKeyGroup.getActivationTime(), new Date()) >= 3) {
                return AjaxResult.error("兑换码只有三个月有效期，现已失效");
            } else if (validityPeriod == 6 && DateUtils.diffMonth(cdKeyGroup.getActivationTime(), new Date()) >= 6) {
                return AjaxResult.error("兑换码只有六个月有效期，现已失效");
            }
        } else {
            return AjaxResult.error("兑换码" + cdKeyGroup.getStatus().getDesc());
        }

        UserExchangeCdKeyVO userExchangeCdKeyVO = exchangeService.exchangeCdKey(cdKey.getKeyId());

        return AjaxResult.success(userExchangeCdKeyVO);
    }

}
