/*
 * Copyright (c) 2018-2999 广州亚米信息科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 */

package com.yami.shop.user.comment.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.enums.ScoreLogType;
import com.yami.shop.bean.model.PointsRecord;
import com.yami.shop.bean.model.UserExtension;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.dao.PointsRecordMapper;
import com.yami.shop.service.UserExtensionService;
import com.yami.shop.bean.dto.ScoreDataDto;
import com.yami.shop.user.comment.model.UserScoreDetail;
import com.yami.shop.user.comment.dao.UserScoreDetailMapper;
import com.yami.shop.user.comment.model.UserScoreLog;
import com.yami.shop.user.comment.service.UserScoreDetailService;
import com.yami.shop.user.comment.service.UserScoreLogService;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lhd
 * @date 2020-05-25 15:31:02
 */
@Service
@AllArgsConstructor
public class UserScoreDetailServiceImpl extends ServiceImpl<UserScoreDetailMapper, UserScoreDetail> implements UserScoreDetailService {

    private final UserScoreDetailMapper scoreDetailMapper;
    private final UserExtensionService userExtensionService;
    private final UserScoreLogService userScoreLogService;
    private final PointsRecordMapper pointsRecordMapper;


    /**
     * 修改用户过期积分
     *
     * @param dateTime 过期时间
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateExpireScoreDetail(DateTime dateTime) {

        // 先修改状态为0的积分明细为过期状态
        scoreDetailMapper.updateExpireScoreDetail(dateTime);

        // 1.查询有积分过期的用户
        List<UserScoreDetail> userScoreDetails = scoreDetailMapper.listExpireScoreDetail(dateTime);
        if (CollectionUtils.isEmpty(userScoreDetails)) {
            return;
        }
        // 2.修改用户积分信息
        Map<String, List<UserScoreDetail>> userScoreMap = userScoreDetails.stream().collect(Collectors.groupingBy(UserScoreDetail::getUserId));
        List<UserScoreLog> logList = new ArrayList<>();
        List<UserExtension> userExtensions = new ArrayList<>();
        for (String userId : userScoreMap.keySet()) {
            List<UserScoreDetail> detailList = userScoreMap.get(userId);
            int expireScore = detailList.stream().mapToInt(UserScoreDetail::getUsableScore).sum();
            UserExtension userExtension = new UserExtension();
            userExtension.setUserId(userId);
            userExtension.setScore(expireScore);
            userExtensions.add(userExtension);

            // 添加积分日志
            UserScoreLog userScoreLog = new UserScoreLog();
            userScoreLog.setUserId(userId);
            userScoreLog.setScore(expireScore);
            userScoreLog.setSource(ScoreLogType.EXPIRE.value());
            userScoreLog.setCreateTime(new Date());
            userScoreLog.setIoType(0);
            logList.add(userScoreLog);
        }
        // 批量修改用户积分和添加积分日志
        if (CollectionUtils.isNotEmpty(userExtensions)) {
            userExtensionService.updateBatchByUserId(userExtensions);
        }
        if (CollectionUtils.isNotEmpty(logList)) {
            userScoreLogService.saveBatch(logList);
        }
        // 3.修改积分明细
        for (UserScoreDetail userScoreDetail : userScoreDetails) {
            userScoreDetail.setStatus(-1);
            userScoreDetail.setExpireTime(new Date());
        }
        updateBatchById(userScoreDetails);
    }

    /**
     * 取消订单时修改用户积分和添加日志
     *
     * @param orderId 订单号
     * @param userId  用户id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateLogAndDetail(Long orderId, String userId) {
        UserExtension userExtension = userExtensionService.getOne(
                new LambdaQueryWrapper<UserExtension>().eq(UserExtension::getUserId, userId));
        if (Objects.isNull(userExtension)) {
            return;
        }
        //修改积分明细
        List<UserScoreDetail> scoreDetails = list(new LambdaUpdateWrapper<UserScoreDetail>()
                .eq(UserScoreDetail::getBizId, orderId).eq(UserScoreDetail::getStatus, 0));
        if (CollectionUtils.isEmpty(scoreDetails)) {
            return;
        }
        //要修改的用户积分，状态为-1表示还没过期的可以返还的用户积分
        Integer score = 0;
        for (UserScoreDetail scoreDetail : scoreDetails) {
            score += scoreDetail.getUsableScore();
            scoreDetail.setStatus(1);
        }
        updateBatchById(scoreDetails);
        userExtension.setScore(userExtension.getScore() + score);
        userExtensionService.updateById(userExtension);
        //添加积分日志
        UserScoreLog scoreLog = new UserScoreLog();
        scoreLog.setUserId(userId);
        scoreLog.setBizId(orderId);
        scoreLog.setScore(score);
        scoreLog.setSource(ScoreLogType.SCORE_CASH.value());
        scoreLog.setCreateTime(DateUtil.date());
        scoreLog.setIoType(1);
        userScoreLogService.save(scoreLog);
    }

    @Override
    public ScoreDataDto doGetUserScore(String userId, Long channelId) {
        return pointsRecordMapper.statisticsAllScorePoint(userId, channelId);
    }

    @Override
    public IPage<PointsRecord> doGetScorePage(PageParam<PointsRecord> page, String userId, Long channelId) {
        IPage<PointsRecord> pointsRecordIPage = pointsRecordMapper.findPage(page,userId,channelId);
        Long l = pointsRecordMapper.statisticsPoint(userId, channelId);
        SimpleDateFormat sdf = new SimpleDateFormat("MM月dd日 HH:mm");
        List<PointsRecord> collect = pointsRecordIPage.getRecords().stream().flatMap((pointsRecord) -> {
            pointsRecord.setCreationDateStr(sdf.format(pointsRecord.getCreationDate()));
            String mark = "";
            List<PointsRecord> recordsToAdd = new ArrayList<>();
            recordsToAdd.add(pointsRecord); // 先添加原对象
            switch (pointsRecord.getPointsType()) {
                case 1:
//                    int variablePoints = pointsRecord.getVariablePoints() != null ?
//                            pointsRecord.getVariablePoints().intValue() : 0;
//                    int remainingPoints = pointsRecord.getPoints().intValue() - variablePoints;
//
//                    if (remainingPoints > 0 && isExpiredToday(pointsRecord.getExpiryDate())) {
//                        PointsRecord expiredRecord = new PointsRecord();
//                        // 复制关键属性（根据实际属性补充）
//                        expiredRecord.setId(pointsRecord.getId()); // 若ID唯一需注意业务逻辑
//                        expiredRecord.setCreationDate(pointsRecord.getCreationDate());
//                        expiredRecord.setPointsType(pointsRecord.getPointsType());
//                        expiredRecord.setPoints(pointsRecord.getPoints());
//                        expiredRecord.setVariablePoints(pointsRecord.getVariablePoints());
//                        expiredRecord.setExpiryDate(pointsRecord.getExpiryDate());
//                        expiredRecord.setCurrentlyAvailablePoints(pointsRecord.getCurrentlyAvailablePoints());
//
//                        // 设置复制对象的显示属性
//                        expiredRecord.setCreationDateStr(pointsRecord.getCreationDateStr()); // 复用已格式化的日期
//                        expiredRecord.setPointsTypeStr("过期扣减"); // 示例：区分类型
//                        expiredRecord.setVariablePointsStr("-" + remainingPoints); // 示例：显示过期数量
//                        // 设置原对象为过期记录
//                        expiredRecord.setPointsTypeStr("过期");
//                        mark = "-";
//                        expiredRecord.setVariablePointsStr(mark +
//                                (pointsRecord.getVariablePoints() != null ?
//                                        pointsRecord.getVariablePoints() : pointsRecord.getPoints()));
//                        recordsToAdd.add(expiredRecord); // 添加复制对象
//                    }
                        pointsRecord.setPointsTypeStr("充值");
                        mark = "+";
                        pointsRecord.setVariablePointsStr(mark + pointsRecord.getPoints());
                    break;
                case 2:
                    pointsRecord.setPointsTypeStr("购物");
                    mark = "-";
                    pointsRecord.setVariablePointsStr(mark +
                            (pointsRecord.getVariablePoints() != null ?
                                    pointsRecord.getVariablePoints() : "0"));
                    break;
                case 3:
//                    if (isExpiredToday(pointsRecord.getExpiryDate())&&pointsRecord.getPointsAudit()!=3) {
//                        PointsRecord expiredRecord = new PointsRecord();
//                        // 复制关键属性（根据实际属性补充）
//                        expiredRecord.setId(pointsRecord.getId()); // 若ID唯一需注意业务逻辑
//                        expiredRecord.setCreationDate(pointsRecord.getCreationDate());
//                        expiredRecord.setPointsType(pointsRecord.getPointsType());
//                        expiredRecord.setPoints(pointsRecord.getPoints());
//                        expiredRecord.setVariablePoints(pointsRecord.getVariablePoints());
//                        expiredRecord.setExpiryDate(pointsRecord.getExpiryDate());
//                        expiredRecord.setCurrentlyAvailablePoints(pointsRecord.getCurrentlyAvailablePoints());
//
//                        // 设置复制对象的显示属性
//                        expiredRecord.setCreationDateStr(pointsRecord.getCreationDateStr()); // 复用已格式化的日期
//                        expiredRecord.setPointsTypeStr("过期扣减"); // 示例：区分类型
//                        if (pointsRecord.getPointsAudit()==1){
//                            expiredRecord.setVariablePointsStr("-" + pointsRecord.getPoints()); // 示例：显示过期数量
//                        } else if (pointsRecord.getPointsAudit()==2) {
//                            expiredRecord.setVariablePointsStr("-" + (pointsRecord.getPoints().intValue()-pointsRecord.getVariablePoints().intValue())); // 示例：显示过期数量
//                        }
//
//                        // 设置原对象为过期记录
//                        expiredRecord.setPointsTypeStr("过期");
//                        recordsToAdd.add(expiredRecord); // 添加复制对象
//                    }
                    pointsRecord.setPointsTypeStr("退款");
                    mark = "+";
                    pointsRecord.setVariablePointsStr(mark + pointsRecord.getPoints());
                    break;
                case 4:
                    if (l==null){
                        pointsRecord.setCurrentlyAvailablePoints(BigDecimal.ZERO);
                    }else {
                        pointsRecord.setCurrentlyAvailablePoints(BigDecimal.valueOf(l));
                    }
                    if (pointsRecord.getOrderNumber()!=null){
                        pointsRecord.setPointsTypeStr("退款过期");
                    }else {
                        pointsRecord.setPointsTypeStr("过期");
                    }
                    mark = "-";
                    pointsRecord.setVariablePointsStr(mark + pointsRecord.getPoints());
                    break;
            }

            // 设置可用积分（原对象和复制对象都会执行）
            if (pointsRecord.getCurrentlyAvailablePoints() != null) {
                pointsRecord.setTotalAvailablePoints(pointsRecord.getCurrentlyAvailablePoints().longValue());
            }
            return recordsToAdd.stream();
        }).collect(Collectors.toList());
        pointsRecordIPage.setRecords(collect);
        return pointsRecordIPage;
    }

    public boolean isExpiredToday(Date expiryDate) {
        if (null == expiryDate) return false;
        LocalDate today = LocalDate.now();
        LocalDate expiryLocalDate = expiryDate.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
        return expiryLocalDate.isBefore(today);
    }

}
