package com.izouma.nineth.service.rewardpoints;

import com.izouma.nineth.config.RedisKeys;
import com.izouma.nineth.domain.User;
import com.izouma.nineth.domain.UserIntegral;
import com.izouma.nineth.domain.UserIntegralChangeLog;
import com.izouma.nineth.dto.PageQuery;
import com.izouma.nineth.enums.IntegralFlag;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.lock.RedisLockable;
import com.izouma.nineth.repo.UserRepo;
import com.izouma.nineth.repo.rewardpoints.UserIntegralChangeLogRepo;
import com.izouma.nineth.repo.rewardpoints.UserIntegralRepo;
import com.izouma.nineth.utils.JpaUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.time.LocalDateTime;
import java.util.Optional;

@Slf4j
@Service
@AllArgsConstructor
public class UserIntegralService {

    private UserRepo userRepo;
    private UserIntegralRepo userIntegralRepo;
    private UserIntegralChangeLogRepo userIntegralChangeLogRepo;


    public Page<UserIntegral> all(PageQuery pageQuery) {
        return userIntegralRepo.findAll(JpaUtils.toSpecification(pageQuery, UserIntegral.class), JpaUtils.toPageRequest(pageQuery));
    }

    /**
     * 获取并初始化用户积分
     * @param userId
     * @return
     */
    @Transactional
    public UserIntegral getAndInitUserIntegral(Long userId){
        UserIntegral userIntegral = null;
        Optional<UserIntegral> userIntegralOptional = userIntegralRepo.findByUserId(userId);
        if(!userIntegralOptional.isPresent()){
            User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
            UserIntegral.UserIntegralBuilder builder  = UserIntegral.builder();
            builder.userId(user.getId())
                    .phone(user.getPhone())
                    .username(user.getUsername())
                    .availableIntegral(0L)
                    .freezeIntegral(0L)
                    .consumeIntegral(0L)
                    .monthConsumeIntegral(0L);
            userIntegral = builder.build();
            userIntegralRepo.saveAndFlush(userIntegral);
        }else{
            userIntegral = userIntegralOptional.get();
        }

        userIntegral = initMonthConsume(userIntegral);

        return userIntegral;
    }

    /**
     * 初始化月统计时间
     * @param userIntegral
     * @return
     */
    @Transactional
    public UserIntegral initMonthConsume(UserIntegral userIntegral){
        LocalDateTime nowMonthStart = LocalDateTime.now().withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0);
        if(userIntegral.getMonthStartTime() == null || userIntegral.getMonthStartTime().compareTo(nowMonthStart) < 0){
            userIntegral.setMonthStartTime(LocalDateTime.now());
            userIntegral.setMonthConsumeIntegral(0L);
            userIntegralRepo.save(userIntegral);
        }

        return userIntegral;
    }

    /**
     * 统一积分变动,所有变动都是基于变动日志而来
     * @param changeLog
     * @return
     */
    @Transactional
    public UserIntegral changeIntegral(UserIntegralChangeLog changeLog){
        Long userId = changeLog.getUserId();
        UserIntegral userIntegral = getAndInitUserIntegral(userId);
        Long availableIntegral = userIntegral.getAvailableIntegral();
        userIntegral.setAvailableIntegral(availableIntegral + changeLog.getIntegral());
        //消耗积分
        if(changeLog.getFlag() == IntegralFlag.DEBIT){
            Long consumeIntegral = userIntegral.getConsumeIntegral();
            userIntegral.setConsumeIntegral(consumeIntegral + Math.abs(changeLog.getIntegral()));
            //月消耗
            Long monthConsumeIntegral = userIntegral.getMonthConsumeIntegral();
            userIntegral.setMonthConsumeIntegral(monthConsumeIntegral + Math.abs(changeLog.getIntegral()));
        }
        userIntegral.setLastChangeTime(LocalDateTime.now());
        userIntegralRepo.saveAndFlush(userIntegral);
        //检查积分
        availableIntegral = userIntegralRepo.getAvailableIntegral(userId);
        if(availableIntegral < 0){
            throw new BusinessException("积分变更失败");
        }
        return userIntegral;
    }


    /**
     * 重新统计积分
     * @param userId
     * @return
     */
    @RedisLockable(prefix= RedisKeys.INTEGRAL_CHANGE_LOCK, key="#userId")
    @Transactional
    public UserIntegral repairIntegral(Long userId){
        UserIntegral userIntegral = getAndInitUserIntegral(userId);
        Long availableIntegral = userIntegralChangeLogRepo.totalAvailableIntegral(userId);
        Long consumeIntegral = userIntegralChangeLogRepo.totalConsumeIntegral(userId);
        userIntegral.setAvailableIntegral(availableIntegral);
        userIntegral.setConsumeIntegral(consumeIntegral);
        userIntegralRepo.saveAndFlush(userIntegral);
        return userIntegral;
    }





}
