package com.jeesharp.business.modules.member.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.jeesharp.business.modules.member.entity.MemberPointsGrantRecord;
import com.jeesharp.business.modules.member.mapper.MemberPointsGrantRecordMapper;
import com.jeesharp.business.modules.member.service.MemberPointsGrantRecordService;
import lombok.AllArgsConstructor;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

/**
 * 积分发放幂等记录领域服务实现。
 *
 * @author jeesharp
 * @since 2026-06-23
 */
@Service
@AllArgsConstructor
@Transactional(readOnly = true)
public class MemberPointsGrantRecordServiceImpl implements MemberPointsGrantRecordService {

    private final MemberPointsGrantRecordMapper memberPointsGrantRecordMapper;

    @Override
    public MemberPointsGrantRecord findActive(String memberId, String sceneCode, String bizId) {
        LambdaQueryWrapper<MemberPointsGrantRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MemberPointsGrantRecord::getMemberId, memberId);
        wrapper.eq(MemberPointsGrantRecord::getSceneCode, sceneCode);
        wrapper.eq(MemberPointsGrantRecord::getBizId, bizId);
        wrapper.eq(MemberPointsGrantRecord::getRevoked, 0);
        wrapper.eq(MemberPointsGrantRecord::getDelFlag, "0");
        wrapper.last("LIMIT 1");
        return memberPointsGrantRecordMapper.selectOne(wrapper);
    }

    @Override
    public long countTodayByMemberAndScene(String memberId, String sceneCode, LocalDate day) {
        LocalDateTime start = day.atStartOfDay();
        LocalDateTime end = day.atTime(LocalTime.MAX);
        LambdaQueryWrapper<MemberPointsGrantRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MemberPointsGrantRecord::getMemberId, memberId);
        wrapper.eq(MemberPointsGrantRecord::getSceneCode, sceneCode);
        wrapper.eq(MemberPointsGrantRecord::getRevoked, 0);
        wrapper.eq(MemberPointsGrantRecord::getDelFlag, "0");
        wrapper.between(MemberPointsGrantRecord::getCreateDate, start, end);
        return memberPointsGrantRecordMapper.selectCount(wrapper);
    }

    @Override
    public long countTotalByMemberAndScene(String memberId, String sceneCode) {
        LambdaQueryWrapper<MemberPointsGrantRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MemberPointsGrantRecord::getMemberId, memberId);
        wrapper.eq(MemberPointsGrantRecord::getSceneCode, sceneCode);
        wrapper.eq(MemberPointsGrantRecord::getRevoked, 0);
        wrapper.eq(MemberPointsGrantRecord::getDelFlag, "0");
        return memberPointsGrantRecordMapper.selectCount(wrapper);
    }

    @Override
    @Transactional(readOnly = false)
    public boolean trySaveRecord(MemberPointsGrantRecord record) {
        try {
            saveRecord(record);
            return true;
        } catch (DuplicateKeyException ex) {
            return false;
        }
    }

    @Override
    @Transactional(readOnly = false)
    public void saveRecord(MemberPointsGrantRecord record) {
        if (StrUtil.isBlank(record.getId())) {
            record.setId(IdUtil.getSnowflakeNextIdStr());
        }
        if (record.getRevoked() == null) {
            record.setRevoked(0);
        }
        record.preInsert();
        if (record.getDelFlag() == null) {
            record.setDelFlag("0");
        }
        memberPointsGrantRecordMapper.insert(record);
    }

    @Override
    @Transactional(readOnly = false)
    public void updatePointsLogId(String id, String pointsLogId) {
        if (StrUtil.isBlank(id)) {
            return;
        }
        LambdaUpdateWrapper<MemberPointsGrantRecord> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(MemberPointsGrantRecord::getId, id);
        wrapper.set(MemberPointsGrantRecord::getPointsLogId, pointsLogId);
        memberPointsGrantRecordMapper.update(null, wrapper);
    }

    @Override
    @Transactional(readOnly = false)
    public void markRevoked(String id) {
        LambdaUpdateWrapper<MemberPointsGrantRecord> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(MemberPointsGrantRecord::getId, id);
        wrapper.set(MemberPointsGrantRecord::getRevoked, 1);
        memberPointsGrantRecordMapper.update(null, wrapper);
    }
}
