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 PublishResourcePointsHandler implements IPointsTaskHandler {

    @Autowired
    private PointsAccountOperations pointsAccountOperations;

    @Autowired
    private ZonePointsAccountMapper zonePointsAccountMapper;

    @Autowired
    private ZonePointsTransactionMapper zonePointsTransactionMapper;

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

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handle(PointsTaskContext ctx) {
        ZonePointsAccount account = pointsAccountOperations.getOrCreateAccount(ctx.getUserId(), ctx.getZoneId());
        if (account == null) {
            logger.warn("积分-资源发布：未能获取积分账户，跳过积分发放 userId={} zoneId={} sourceId={}",
                    ctx.getUserId(), ctx.getZoneId(), ctx.getSourceId());
            return;
        }

        // 幂等检查：同一资源发布同一用户只发放一次
        if (zonePointsTransactionMapper.countByEventTypeAndSourceAndUser(ZoneConstants.PublishResource.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.PublishResource.POINTS;
        int frozenAfter = locked.getFrozenPoints();

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

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