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

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
import com.yonge.cooleshow.biz.dal.dto.UserParam;
import com.yonge.cooleshow.biz.dal.entity.CouponInfo;
import com.yonge.cooleshow.biz.dal.entity.CouponIssue;
import com.yonge.cooleshow.biz.dal.entity.SysUser;
import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
import com.yonge.cooleshow.biz.dal.enums.InOrOutEnum;
import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
import com.yonge.cooleshow.biz.dal.enums.SendTypeEnum;
import com.yonge.cooleshow.biz.dal.enums.coupon.CouponUseStateEnum;
import com.yonge.cooleshow.biz.dal.mapper.CouponIssueMapper;
import com.yonge.cooleshow.biz.dal.mapper.SysUserMapper;
import com.yonge.cooleshow.biz.dal.queryInfo.CouponInfoQuery;
import com.yonge.cooleshow.biz.dal.queryInfo.CouponIssueQueryInfo;
import com.yonge.cooleshow.biz.dal.service.CouponInfoService;
import com.yonge.cooleshow.biz.dal.service.CouponIssueService;
import com.yonge.cooleshow.biz.dal.service.SysMessageService;
import com.yonge.cooleshow.biz.dal.vo.CouponIssueUserVo;
import com.yonge.cooleshow.biz.dal.vo.coupon.CouponInfoWrapper;
import com.yonge.cooleshow.biz.dal.vo.coupon.CouponIssueWrapper;
import com.yonge.cooleshow.biz.dal.wrapper.StatGroupWrapper;
import com.yonge.cooleshow.common.enums.EStatus;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
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 java.text.MessageFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 优惠券发放 服务实现类
 * </p>
 *
 * @author Eric
 * @since 2022-09-02
 */
@Service
public class CouponIssueServiceImp extends ServiceImpl<CouponIssueMapper, CouponIssue> implements CouponIssueService {

    private static final Logger log = LoggerFactory.getLogger(CouponIssueServiceImp.class);
    @Autowired
    private CouponInfoService couponInfoService;
    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysUserFeignService sysUserFeignService;

    @Autowired
    private SysMessageService sysMessageService;


    @Override
    public IPage<CouponIssueWrapper> queryCouponIssueInfo(IPage<CouponIssueWrapper> page, CouponIssueQueryInfo query) {
        List<CouponIssueWrapper> couponIssueWrappers = baseMapper.queryCouponIssueInfo(page, query);


        // 优惠券过期状态
        couponIssueWrappers = couponIssueWrappers.stream()
                .peek(x -> {
                    if (StringUtils.isEmpty(x.getOrderNo())
                            && CouponUseStateEnum.WITHDRAW != x.getUseState()
                            && x.getEndTime().compareTo(query.getExpiredTime()) <0) {
                        x.setUseState(CouponUseStateEnum.EXPIRED);
                    }
                }).collect(Collectors.toList());

        // 查看人员信息
        List<Long> userIdList = couponIssueWrappers.stream()
                                                     .map(CouponIssueWrapper::getUserId)
                                                     .collect(Collectors.toList());
        List<SysUser> userList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(userIdList)) {
            userList = sysUserMapper.selectBatchIds(userIdList);
        }
        Map<Long, List<SysUser>> userMap = userList.stream().collect(Collectors.groupingBy(SysUser::getId));


        // 获取发放人信息
        List<Long> issuerIdList = couponIssueWrappers.stream()
                                                .map(CouponIssueWrapper::getIssuer)
                                                .collect(Collectors.toList());
        List<SysUser> issuerList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(issuerIdList)) {
            issuerList = sysUserMapper.selectBatchIds(issuerIdList);
        }

        Map<Long, List<SysUser>> issuerMap = issuerList.stream().collect(Collectors.groupingBy(SysUser::getId));



        // 可用优惠券数量
        long count  = 0 ;
        if (query.getAmount() != null) {

             count= couponIssueWrappers.stream()
                                            .filter(couponIssueWrapper -> couponIssueWrapper.getUseLimit()
                                                                                            .compareTo(query.getAmount()) <= 0)
                                            .count();
        }
        for (CouponIssueWrapper couponIssueWrapper : couponIssueWrappers) {
            List<SysUser> issuer = issuerMap.get(couponIssueWrapper.getIssuer());
            if (!CollectionUtils.isEmpty(issuer)) {
                couponIssueWrapper.setIssueRealName(issuer.get(0).getRealName());
                couponIssueWrapper.setIssueUsername(issuer.get(0).getUsername());
            }

            List<SysUser> users = userMap.get(couponIssueWrapper.getUserId());
            if (!CollectionUtils.isEmpty(users)) {
                couponIssueWrapper.setUsername(users.get(0).getUsername());
                couponIssueWrapper.setRealName(users.get(0).getRealName());
                couponIssueWrapper.setPhone(users.get(0).getPhone());
                couponIssueWrapper.setUsable(count);
            }
        }

        return page.setRecords(couponIssueWrappers);


    }

    @Override
    @Transactional
    public Boolean withdrawCoupon(Long couponIssueId) {

        // 测回退库存
        CouponIssue couponIssue = getById(couponIssueId);
        couponInfoService.updateStock(couponIssue.getCouponId(),1,InOrOutEnum.IN);

        return this.lambdaUpdate()
                .eq(CouponIssue::getId,couponIssueId)
                .set(CouponIssue::getStatus, EStatus.DISABLE.getValue())
                .set(CouponIssue::getUseState,CouponUseStateEnum.WITHDRAW)
                .update();
    }

    @Override
    @Transactional
    public void issueCoupon(Long couponId, List<UserParam> userParam, Long issuer, String reason,SendTypeEnum issueWay, Date date) {
        CouponInfo couponInfo = couponInfoService.queryCouponInfoById(couponId);
        if (couponInfo == null) {
            throw new BizException("未找到优惠券信息");
        }
        if (couponInfo.getInventory() < userParam.size()) {
            throw new BizException("库存不足");
        }
        if (couponInfo.getStatus() == EStatus.DISABLE.getValue()) {
            throw new BizException("优惠券已被禁用");
        }

        List<Long> userIds = userParam.stream()
                .map(UserParam::getUserId).distinct().collect(Collectors.toList());
        // 判断用户领取数据限制
        if (Optional.ofNullable(couponInfo.getQuantityLimit()).orElse(0) > 0
                && CollectionUtils.isNotEmpty(userIds)) {

            CouponInfoQuery.IssueStatQuery statQuery = CouponInfoQuery.IssueStatQuery.builder().userIds(userIds).build();
            // 统计用户领取优惠券数量
            List<StatGroupWrapper> groupWrappers = getBaseMapper().selectCouponIssueStatInfo(couponId, statQuery);

            if (groupWrappers.stream().anyMatch(x -> x.getTotal() >= couponInfo.getQuantityLimit())) {
                throw new BizException(MessageFormat.format("优惠券已领取，每人仅限{0}张", couponInfo.getQuantityLimit()));
            }
        }

        saveIssueCoupon(couponId, userParam, issuer, reason, issueWay, date);

        //  优惠券扣减库存
        int i = couponInfoService.updateStock(couponId, userParam.size(), InOrOutEnum.OUT);
        if (i == 0) {
            throw new BizException("库存不足");
        }

        // 发送消息
        sendMessage(couponInfo.getName(), userParam);
    }

    @Override
    public void saveIssueCoupon(Long couponId, List<UserParam> userParam, Long issuer, String reason, SendTypeEnum issueWay, Date date) {
        CouponInfo couponInfo = couponInfoService.queryCouponInfoById(couponId);
        // 判断优惠券类型 设置优惠券时间
        Long startTime = null;
        Long endTime = null;
        if (couponInfo.getValidDay() != null && couponInfo.getValidDay() >0) {
            startTime =LocalDateTime.of(LocalDate.now(), LocalTime.MIN).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
            endTime = LocalDateTime.of(LocalDate.now().plusDays(couponInfo.getValidDay()-1), LocalTime.MAX)
                                   .atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        } else {
            startTime = couponInfo.getStartTime();
            endTime = couponInfo.getEndTime();
        }
        List<CouponIssue> couponIssueList = new ArrayList<>();
        for (UserParam param : userParam) {
            if (param.getUserId() == null) {
                throw new BizException("发放用户id不能为空");
            }
            if (param.getClientType() == null) {
                throw new BizException("发放客户端不能为空");
            }
            CouponIssue couponIssue = new CouponIssue();
            couponIssue.setCouponId(couponId);
            couponIssue.setIssuer(issuer);
            couponIssue.setIssueTime(date.toInstant().toEpochMilli());
            couponIssue.setIssueWay(issueWay.getCode());
            couponIssue.setRemark(reason);
            couponIssue.setStartTime(startTime);
            couponIssue.setEndTime(endTime);
            couponIssue.setUseState(CouponUseStateEnum.USABLE);
            couponIssue.setClientType(param.getClientType().getCode());
            couponIssue.setUserId(param.getUserId());
            couponIssue.setStatus(1);
            couponIssueList.add(couponIssue);
        }
        this.saveBatch(couponIssueList);
    }

    private void sendMessage(String couponName,List<UserParam> userParams) {
        for (UserParam userParam : userParams) {

            try {
                com.yonge.cooleshow.auth.api.entity.SysUser sysUser = getSysUser(userParam.getUserId());
                // 推送老师
                Map<Long, String> teacherReceivers = new HashMap<>();
                teacherReceivers.put(sysUser.getId(), sysUser.getPhone());

                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.COUPON_ISSUE, teacherReceivers, null,
                                                   0, null, userParam.getClientType().getCode(),couponName);

            } catch (Exception e) {
                log.error("发放优惠券消息发送失败 -->{}",e.fillInStackTrace());
            }

        }
    }

    private com.yonge.cooleshow.auth.api.entity.SysUser getSysUser(Long userId) {
        return Optional.ofNullable(userId)
                       .map(sysUserFeignService::queryUserById)
                       .orElseThrow(() -> new BizException("用户不存在"));
    }

    @Override
    public IPage<CouponIssueUserVo> queryUser(IPage<CouponIssueUserVo> iPage, Long couponId, ClientEnum client, String keyword) {
        CouponInfo couponInfo = couponInfoService.getById(couponId);
        if (couponInfo == null) {
            throw new BizException("未找到优惠券信息");
        }
        if (client == null) {
            client = couponInfo.getClientType();
        }

        List<CouponIssueUserVo> list = sysUserMapper.queryCouponIssueUser(iPage,client, keyword);

        return iPage.setRecords(list);


    }

    /**
     * 统计用户优惠券状态
     *
     * @param id         用户ID
     * @param query     CouponInfoQuery.CouponStateStatQuery
     * @return List<CouponInfoWrapper.CouponStat>
     */
    @Override
    public List<CouponInfoWrapper.CouponStat> queryCouponStateStatInfo(Long id, CouponInfoQuery.CouponStateStatQuery query) {

        List<CouponInfoWrapper.CouponStat> couponStats = Lists.newCopyOnWriteArrayList();

        // 优惠券统计状态
        /*Map<String, Integer> collect = getBaseMapper().selectCouponStateStatInfo(id, query).stream()
                .collect(Collectors.toMap(StatGroupWrapper::getGid, StatGroupWrapper::getTotal, (o, n) -> n));

        CouponUseStateEnum[] values = CouponUseStateEnum.values();
        for (CouponUseStateEnum item : values) {

            couponStats.add(CouponInfoWrapper.CouponStat.builder()
                    .useState(item)
                    .total(collect.getOrDefault(item.getCode(), 0))
                    .build());
        }*/

        // 分享统计优惠状态数
        Lists.newArrayList(CouponUseStateEnum.values()).parallelStream().forEach(item -> {

            CouponInfoQuery.CouponStateStatQuery queryParam = CouponInfoQuery.CouponStateStatQuery.from(query.jsonString())
                    .timestamp(DateTime.now().getMillis())
                    .userState(item);

            int sum = getBaseMapper().selectCouponStateStatInfo(id, queryParam).stream()
                    .mapToInt(StatGroupWrapper::getTotal).sum();

            couponStats.add(CouponInfoWrapper.CouponStat.builder().useState(item).total(sum).build());
        });

        return couponStats;
    }
}
