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.jeesharp.business.modules.member.entity.MemberPointsLog;
import com.jeesharp.business.modules.member.enums.MemberPointsTypeEnum;
import com.jeesharp.business.modules.member.mapper.MemberPointsLogMapper;
import com.jeesharp.business.modules.member.service.MemberPointsLogService;
import com.jeesharp.business.modules.member.vo.MemberPointsLogQueryVO;
import com.jeesharp.framework.mybatis.core.service.CrudService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 会员积分流水领域服务实现。
 *
 * @author jeesharp
 * @since 2026-06-09
 */
@Service
@Transactional(readOnly = true)
public class MemberPointsLogServiceImpl
        extends CrudService<MemberPointsLogMapper, MemberPointsLog, MemberPointsLogQueryVO>
        implements MemberPointsLogService {

    @Override
    @Transactional(readOnly = false)
    public void appendLog(MemberPointsLog log) {
        if (log.getId() == null) {
            log.setId(IdUtil.getSnowflakeNextIdStr());
        }
        log.preInsert();
        if (log.getDelFlag() == null) {
            log.setDelFlag("0");
        }
        if (StrUtil.isBlank(log.getOperateSource())) {
            log.setOperateSource("SYSTEM");
        }
        getBaseMapper().insert(log);
    }

    @Override
    @Transactional(readOnly = false)
    public void recordChange(String memberId, MemberPointsTypeEnum pointsType, int delta,
                             int beforePoints, int afterPoints,
                             String bizType, String bizId, String bizDesc) {
        if (delta <= 0) {
            return;
        }
        int signedPoints = switch (pointsType) {
            case SPEND, EXPIRE -> -delta;
            default -> delta;
        };
        MemberPointsLog log = new MemberPointsLog();
        log.setMemberId(memberId);
        log.setPointsType(pointsType.getValue());
        log.setPoints(signedPoints);
        log.setBeforePoints(beforePoints);
        log.setAfterPoints(afterPoints);
        log.setBizType(bizType);
        log.setBizId(bizId);
        log.setBizDesc(bizDesc);
        appendLog(log);
    }

    @Override
    @Transactional(readOnly = false)
    public String recordChangeWithRule(String memberId, MemberPointsTypeEnum pointsType, int delta,
                                       int beforePoints, int afterPoints,
                                       String bizType, String bizId, String bizDesc,
                                       String ruleId, String ruleName,
                                       java.time.LocalDateTime expireDate, String operateSource) {
        if (delta <= 0) {
            return null;
        }
        int signedPoints = switch (pointsType) {
            case SPEND, EXPIRE -> -delta;
            default -> delta;
        };
        MemberPointsLog log = new MemberPointsLog();
        log.setMemberId(memberId);
        log.setPointsType(pointsType.getValue());
        log.setPoints(signedPoints);
        log.setBeforePoints(beforePoints);
        log.setAfterPoints(afterPoints);
        log.setBizType(bizType);
        log.setBizId(bizId);
        log.setBizDesc(bizDesc);
        log.setRuleId(ruleId);
        log.setRuleName(ruleName);
        log.setExpireDate(expireDate);
        if (StrUtil.isNotBlank(operateSource)) {
            log.setOperateSource(operateSource);
        }
        appendLog(log);
        return log.getId();
    }

    @Override
    public List<MemberPointsLog> listRecentByMember(String memberId, int limit) {
        int cap = Math.min(Math.max(limit, 1), 500);
        LambdaQueryWrapper<MemberPointsLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MemberPointsLog::getMemberId, memberId);
        wrapper.eq(MemberPointsLog::getDelFlag, "0");
        wrapper.orderByDesc(MemberPointsLog::getCreateDate);
        wrapper.last("LIMIT " + cap);
        return getBaseMapper().selectList(wrapper);
    }
}
