package org.dromara.zjk.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.zjk.domain.ZjkExpert;
import org.dromara.zjk.domain.ZjkPoint;
import org.dromara.zjk.domain.ZjkPointRule;
import org.dromara.zjk.domain.ZjkPointUser;
import org.dromara.zjk.domain.dto.PointInfoDto;
import org.dromara.zjk.domain.dto.PointReqDto;
import org.dromara.zjk.domain.vo.*;
import org.dromara.zjk.enums.PointTrendEnum;
import org.dromara.zjk.mapper.ZjkExpertMapper;
import org.dromara.zjk.mapper.ZjkPointMapper;
import org.dromara.zjk.mapper.ZjkPointRuleMapper;
import org.dromara.zjk.mapper.ZjkPointUserMapper;
import org.dromara.zjk.service.ZjkPointRewardService;
import org.dromara.zjk.service.ZjkPointUserService;
import org.dromara.zjk.utils.DateRangUtils;
import org.dromara.zjk.zwy.client.HmacClient;
import org.dromara.zjk.zwy.utils.ObjectHashGenerator;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author EDY
 * @description 针对表【zjk_point_user(积分用户)】的数据库操作Service实现
 * @createDate 2024-11-06 16:29:59
 */
@Service
@Slf4j
public class ZjkPointUserServiceImpl extends ServiceImpl<ZjkPointUserMapper, ZjkPointUser>
    implements ZjkPointUserService {
    @Resource
    private ZjkPointMapper zjkPointMapper;
    @Resource
    private ZjkPointRuleMapper zjkPointRuleMapper;
    @Resource
    private ZjkPointUserMapper zjkPointUserMapper;
    @Resource
    private ZjkExpertMapper zjkExpertMapper;
    @Resource
    private ZjkPointRewardService zjkPointRewardService;

    @Resource
    private HmacClient hmacClient;


    /**
     * 统计用户积分单条记录
     *
     * @return
     */
/*    @Override
    @Transactional
    public boolean savePointInfo(PointInfoDto dto) {
        //插入单条积分记录
        QueryWrapper<ZjkPointRule> wq = new QueryWrapper<>();
        wq.lambda().eq(ZjkPointRule::getRuleKey, dto.getRuleKey());
        ZjkPointRule zjkPointRule = zjkPointRuleMapper.selectOne(wq);
        ZjkPoint zjkPoint = new ZjkPoint();
        zjkPoint.setEvaluateId(dto.getEvaluateId());
        zjkPoint.setPoints(dto.getPoints());
        zjkPoint.setRuleId(zjkPointRule.getId());
        zjkPoint.setExpertId(dto.getExpertId());
        zjkPoint.setUserId(dto.getUserId());
        int insert = zjkPointMapper.insert(zjkPoint);
        //更新总分值记录
        QueryWrapper<ZjkPointUser> zj = new QueryWrapper<>();
        zj.lambda().eq(ZjkPointUser::getUserId, dto.getUserId());
        ZjkPointUser zjkPointUser = zjkPointUserMapper.selectOne(zj);
        if (zjkPointUser == null) {
            //初始新增
            ZjkPointUser pu = new ZjkPointUser();
            pu.setExpertId(dto.getExpertId());
            pu.setUserId(dto.getUserId());
            pu.setPointCount(dto.getPoints());
            pu.setExpertId(dto.getExpertId());
            zjkPointUserMapper.insert(pu);
        } else {
            //分值修改
            zjkPointUser.setChangeTime(new Date());
            zjkPointUser.setPointCount(zjkPointUser.getPointCount().add(dto.getPoints()));
            //获取奖励设置
            zjkPointUserMapper.updateById(zjkPointUser);
        }
        boolean res = false;
        if (insert == 1) {
            res = true;
        }
        return res;
    }*/
    @Override
    @Transactional
    public boolean savePointInfo(PointInfoDto dto) {
        // 查询积分规则
        QueryWrapper<ZjkPointRule> wq = new QueryWrapper<>();
        wq.lambda().eq(ZjkPointRule::getRuleKey, dto.getRuleKey());
        ZjkPointRule zjkPointRule = zjkPointRuleMapper.selectOne(wq);

        // 构造并插入 ZjkPoint
        ZjkPoint zjkPoint = new ZjkPoint();
        zjkPoint.setEvaluateId(dto.getEvaluateId());
        zjkPoint.setPoints(dto.getPoints());
        zjkPoint.setRuleId(zjkPointRule.getId());
        zjkPoint.setExpertId(dto.getExpertId());
        zjkPoint.setUserId(dto.getUserId());

        int insert = zjkPointMapper.insert(zjkPoint);

        // 插入成功后再 select 出该记录（使用主键）
        if (insert == 1) {
            ZjkPoint inserted = zjkPointMapper.selectById(zjkPoint.getId()); // 获取主键后自动回填
            // 生成 HMAC
            String hash = ObjectHashGenerator.generateHash(inserted);
            String base64 = Base64.getEncoder().encodeToString(hash.getBytes(StandardCharsets.UTF_8));
             String hmac = hmacClient.calculateHmac(base64);
//            String hmac = base64;

            // 回写 HMAC
            ZjkPoint updateHmac = new ZjkPoint();
            updateHmac.setId(inserted.getId());
            updateHmac.setHmac(hmac);
            zjkPointMapper.updateById(updateHmac);
        }

        // 处理总积分记录
        QueryWrapper<ZjkPointUser> zj = new QueryWrapper<>();
        zj.lambda().eq(ZjkPointUser::getUserId, dto.getUserId());
        ZjkPointUser zjkPointUser = zjkPointUserMapper.selectOne(zj);

        if (zjkPointUser == null) {
            ZjkPointUser pu = new ZjkPointUser();
            pu.setExpertId(dto.getExpertId());
            pu.setUserId(dto.getUserId());
            pu.setPointCount(dto.getPoints());
            zjkPointUserMapper.insert(pu);
        } else {
            zjkPointUser.setChangeTime(new Date());
            zjkPointUser.setPointCount(zjkPointUser.getPointCount().add(dto.getPoints()));
            zjkPointUserMapper.updateById(zjkPointUser);
        }

        return insert == 1;
    }


    @Override
    public TableDataInfo<PointShowVO> queryPointList(PointReqDto bo, PageQuery pageQuery) {
        IPage<PointShowVO> page = zjkPointMapper.queryPointList(pageQuery.build(), bo);
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<ZjkPointVO> queryPointDetail(PointReqDto bo, PageQuery pageQuery) {
        IPage<ZjkPointVO> page = zjkPointMapper.queryPointDetail(pageQuery.build(), bo);
        return TableDataInfo.build(page);
    }

    @Override
    public R<Void> deleteRecord(Long id, String expertId) {
        //删除记录
        ZjkPoint zjkPoint = zjkPointMapper.selectById(id);
        zjkPointMapper.deleteById(id);
        //总分更新
        QueryWrapper<ZjkPointUser> zj = new QueryWrapper<>();
        zj.lambda().eq(ZjkPointUser::getExpertId, expertId);
        ZjkPointUser zjkPointUser = zjkPointUserMapper.selectOne(zj);
        if (zjkPointUser != null) {
            BigDecimal subtract = zjkPointUser.getPointCount().subtract(zjkPoint.getPoints());
            zjkPointUser.setPointCount(subtract);
            zjkPointUser.setChangeTime(new Date());
            zjkPointUserMapper.updateById(zjkPointUser);
        }
        return R.ok();
    }

    @Override
    public R<PointTrendVO> getPointTrend(String dayKey, String expertId) {
        PointTrendVO pointTrendVO = new PointTrendVO();
        List<String> daysRange = DateRangUtils.getDaysRange(PointTrendEnum.getDayByCode(dayKey));
        List<BigDecimal> collect = daysRange.stream().map(item -> {
            BigDecimal point = zjkPointMapper.getPointByDate(item, expertId);
            if(point==null){
                point= new BigDecimal(0);
            }
            return point;
        }).collect(Collectors.toList());
        pointTrendVO.setPointY(collect);
        pointTrendVO.setDayX(daysRange);
        return R.ok(pointTrendVO);
    }

    @Override
    public R<Void> pointCheck(ZjkPointUser dto) {
        UpdateWrapper<ZjkPointUser> wq = new UpdateWrapper<>();
        wq.lambda().eq(ZjkPointUser::getExpertId, dto.getExpertId())
            .set(dto.getCheckStatus() != null, ZjkPointUser::getCheckStatus, dto.getCheckStatus())
            .set(dto.getRemark()!=null,ZjkPointUser::getRemark,dto.getRemark());
        int update = zjkPointUserMapper.update(wq);
        if (update == 1) {
            return R.ok();
        } else {
            return R.fail();

        }
    }

    @Override
    public R<PointBaseVO> getPointBase() {
        LambdaQueryWrapper<ZjkExpert> wq = new LambdaQueryWrapper<ZjkExpert>()
            .eq(ZjkExpert::getUserId, LoginHelper.getUserId())
            .eq(ZjkExpert::getDeleteFlag, UserConstants.DEL_FLAG_NORMAL)
            .eq(ZjkExpert::getStatus, 2);
        ZjkExpert zjkExpert = zjkExpertMapper.selectOne(wq);
        if (zjkExpert != null) {
            PointBaseVO result = new PointBaseVO();
            BeanUtil.copyProperties(zjkExpert, result);
            //积分title设置
            QueryWrapper<ZjkPointUser> zj = new QueryWrapper<>();
            zj.lambda().eq(ZjkPointUser::getUserId, LoginHelper.getUserId());
            PointShowVO rdata = zjkPointUserMapper.getRankAndPoint(LoginHelper.getUserId());
            if(rdata!=null){
                result.setPoints(rdata.getPoints());
                result.setRank(rdata.getRank());
                result.setRewardTitle(zjkPointRewardService.getRewardTitle(rdata.getExpertId(), rdata.getPoints()));
                result.setCheckStatus(rdata.getCheckStatus());
            }
            return R.ok(result);
        }

        return R.fail("当前用户还未入专家库");
    }

    @Override
    public R<PointExpertRankVO> getExpertPointRank(Integer rangeDay) {
        Date daysAgo = DateUtil.offsetDay(new Date(), -rangeDay+1);
        List<PointExpertGetVO> res = zjkPointUserMapper.getExpertPointRank(daysAgo);
        PointExpertRankVO pointExpertRankVO = new PointExpertRankVO();
        List<String> pointY = res.stream().map(item -> item.getExpertName()).collect(Collectors.toList());
        List<BigDecimal> pointX = res.stream().map(item -> item.getPoints()).collect(Collectors.toList());
        pointExpertRankVO.setNameY(pointY);
        pointExpertRankVO.setPointX(pointX);

        return R.ok(pointExpertRankVO);
    }

    @Override
    public TableDataInfo<PointShowVO> checkPointList(PointReqDto bo, PageQuery pageQuery) {
        //积分低于10分，且保持至少3个月的专家需要进行审核；
        //积分排行榜前10名每7天需要进行一次审核；
        Date daysAgo = DateUtil.offsetDay(new Date(), -89);
        bo.setMonthCheckDate(daysAgo);
        Date checkAgo = DateUtil.offsetDay(new Date(), -6);
        bo.setWeekCheckDate(checkAgo);
        IPage<PointShowVO> page = zjkPointMapper.getCheckPointList(pageQuery.build(), bo);
        return TableDataInfo.build(page);
    }
    @Override
    public void handleWaitCheckPointStatus(){
        PointReqDto bo = new PointReqDto();
        //积分低于10分，且保持至少3个月的专家需要进行审核；
        //积分排行榜前10名每7天需要进行一次审核；
        Date daysAgo = DateUtil.offsetDay(new Date(), -89);
        bo.setMonthCheckDate(daysAgo);
        Date checkAgo = DateUtil.offsetDay(new Date(), -6);
        bo.setWeekCheckDate(checkAgo);
        List<PointShowVO> checkWaitPointList = zjkPointMapper.getCheckWaitPointList(bo);
        if(!CollectionUtils.isEmpty(checkWaitPointList)){
            List<String> ids = checkWaitPointList.stream().map(PointShowVO::getId).collect(Collectors.toList());
            UpdateWrapper<ZjkPointUser> wq = new UpdateWrapper<>();
            wq.lambda().in(!CollectionUtils.isEmpty(ids),ZjkPointUser::getId, ids)
                .set(ZjkPointUser::getCheckStatus, UserConstants.CHECK_STATUS_WAIT);
            int update = zjkPointUserMapper.update(wq);
            log.info("====积分待审核更新人数:"+update);
        }

    }

}




