package com.microservices.zone.member.service.points.handler;

import com.microservices.zone.member.domain.points.ZonePointsAccount;
import com.microservices.zone.member.mapper.ZonePointsAccountMapper;
import com.microservices.zone.member.mapper.ZonePointsTransactionMapper;
import com.microservices.zone.member.service.points.IPointsTaskHandler;
import com.microservices.zone.member.service.points.PointsAccountOperations;
import com.microservices.zone.member.service.points.PointsTaskContext;
import com.microservices.zone.utils.ZoneConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * 关联项目 — 积分奖励
 *
 * @author otto
 */
@Component
public class RelevanceProjectPointsHandler implements IPointsTaskHandler {

    @Autowired
    private PointsAccountOperations pointsAccountOperations;

    @Autowired
    private ZonePointsAccountMapper zonePointsAccountMapper;

    @Autowired
    private ZonePointsTransactionMapper zonePointsTransactionMapper;

    private static final Logger logger = LoggerFactory.getLogger(RelevanceProjectPointsHandler.class);

    @Override
    public String getSourceType() {
        return ZoneConstants.RelevanceProject.SOURCE_TYPE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handle(PointsTaskContext ctx) {
        ZonePointsAccount account = pointsAccountOperations.getOrCreateAccount(ctx.getUserId(), ctx.getZoneId());
        if (account == null) {
            return;
        }

        // 幂等检查：同一项目关联同一用户只发放一次
        if (zonePointsTransactionMapper.countByEventTypeAndSourceAndUser(ZoneConstants.RelevanceProject.SOURCE_TYPE, ctx.getSourceId(), account.getId()) > 0) {
            logger.info("积分-关联项目：积分已发放，跳过 sourceId={} userId={}", ctx.getSourceId(), ctx.getUserId());
            return;
        }

        ZonePointsAccount locked = zonePointsAccountMapper.selectZonePointsAccountByIdForUpdate(account.getId());
        int availableAfter = locked.getAvailablePoints() + ZoneConstants.RelevanceProject.POINTS;
        int frozenAfter = locked.getFrozenPoints();

        zonePointsAccountMapper.addPointsAtomic(account.getId(), ZoneConstants.RelevanceProject.POINTS);

        pointsAccountOperations.recordPointsTransaction(account.getId(),
                ZoneConstants.TransactionType.ADD,
                ZoneConstants.RelevanceProject.POINTS,
                availableAfter, frozenAfter,
                ZoneConstants.RelevanceProject.REASON, ctx.getOperatorId(), ctx.getSourceId(),
                ZoneConstants.RelevanceProject.SOURCE_TYPE, null,
                ZoneConstants.RelevanceProject.SUBJECT,
                String.format(ZoneConstants.RelevanceProject.SUBJECT_DESC_TEMPLATE, ctx.getSubjectDesc()),
                null);
    }
}
