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

import com.alibaba.fastjson2.JSONObject;
import com.microservices.common.core.constant.SecurityConstants;
import com.microservices.common.core.utils.DateUtils;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.system.api.RemoteCmsService;
import com.microservices.zone.member.domain.points.ZonePointsAccount;
import com.microservices.zone.member.domain.points.ZonePointsDoc;
import com.microservices.zone.member.mapper.ZonePointsAccountMapper;
import com.microservices.zone.member.mapper.ZonePointsDocMapper;
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;

/**
 * 文章浏览阅读量奖励 — 每满 100 次阅读触发积分
 *
 * @author otto
 */
@Component
public class DocVisitsPointsHandler implements IPointsTaskHandler {
    private static final Logger logger = LoggerFactory.getLogger(DocVisitsPointsHandler.class);

    @Autowired
    private PointsAccountOperations pointsAccountOperations;

    @Autowired
    private ZonePointsAccountMapper zonePointsAccountMapper;

    @Autowired
    private ZonePointsDocMapper zonePointsDocMapper;

    @Autowired
    private RemoteCmsService remoteCmsService;

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handle(PointsTaskContext ctx) {
        // CMS 侧写入任务时不携带 zoneId，需通过 deptId 解析补齐
        pointsAccountOperations.resolveZoneId(ctx);

        ZonePointsAccount account = pointsAccountOperations.getOrCreateAccount(ctx.getUserId(), ctx.getZoneId());
        if (account == null) {
            return;
        }

        int totalVisits = 0;
        if (StringUtils.isNotEmpty(ctx.getSourceData())) {
            totalVisits = Integer.parseInt(ctx.getSourceData());
        }

        ZonePointsDoc pointsDoc = zonePointsDocMapper.selectZonePointsDocByZoneIdAndDocId(ctx.getZoneId(), ctx.getSourceId());
        if (pointsDoc == null) {
            // 首次触发：创建记录
            ZonePointsDoc newDoc = new ZonePointsDoc();
            newDoc.setZoneId(ctx.getZoneId());
            newDoc.setDocId(ctx.getSourceId());
            newDoc.setPointsStartVisits(totalVisits - 1);
            newDoc.setPointsTriggerCount(0);
            newDoc.setUserId(ctx.getUserId());
            newDoc.setCreateTime(DateUtils.getNowDate());
            zonePointsDocMapper.insertZonePointsDoc(newDoc);
        } else {
            if (pointsDoc.getPointsTriggerCount() >= ZoneConstants.DocVisits.MAX_TRIGGER_COUNT) {
                logger.info("积分-文章浏览：已达触发上限 zoneId={} docId={} triggerCount={}",
                        ctx.getZoneId(), ctx.getSourceId(), pointsDoc.getPointsTriggerCount());
                return;
            }

            int startVisits = pointsDoc.getPointsStartVisits() != null ? pointsDoc.getPointsStartVisits() : 0;
            boolean needUpdateStartVisits = false;
            if (pointsDoc.getPointsStartVisits() == null) {
                try {
                    JSONObject cmsDoc = remoteCmsService.selectCmsDocJSONObjectById(ctx.getSourceId(), SecurityConstants.INNER).getData();
                    if (cmsDoc != null && cmsDoc.getLong("visits") != null) {
                        startVisits = cmsDoc.getLong("visits").intValue();
                        needUpdateStartVisits = true;
                    }
                } catch (Exception e) {
                    logger.warn("积分-文章浏览：远程查询cms_doc失败，跳过此次积分 userId={} docId={} error={}",
                            ctx.getUserId(), ctx.getSourceId(), e.getMessage());
                    return;
                }
            }

            // 如果通过远程查询获取到了cms_doc的visits，则同步更新到数据库
            if (needUpdateStartVisits) {
                pointsDoc.setPointsStartVisits(startVisits);
                zonePointsDocMapper.updateZonePointsDoc(pointsDoc);
            }

            int currentVisits = totalVisits - startVisits;
            int totalExpected = currentVisits / ZoneConstants.DocVisits.TRIGGER_VISITS;

            if (totalExpected > pointsDoc.getPointsTriggerCount()) {
                ZonePointsAccount locked = zonePointsAccountMapper.selectZonePointsAccountByIdForUpdate(account.getId());
                int availableAfter = locked.getAvailablePoints() + ZoneConstants.DocVisits.POINTS_PER_TRIGGER;
                int frozenAfter = locked.getFrozenPoints();

                zonePointsAccountMapper.addPointsAtomic(account.getId(), ZoneConstants.DocVisits.POINTS_PER_TRIGGER);

                pointsAccountOperations.recordPointsTransaction(account.getId(),
                        ZoneConstants.TransactionType.ADD,
                        ZoneConstants.DocVisits.POINTS_PER_TRIGGER,
                        availableAfter, frozenAfter,
                        String.format(ZoneConstants.DocVisits.REASON_TEMPLATE, ZoneConstants.DocVisits.POINTS_PER_TRIGGER, pointsDoc.getPointsTriggerCount() * 2 + 2),
                        0L, ctx.getSourceId(), ZoneConstants.DocVisits.SOURCE_TYPE, null,
                        ZoneConstants.DocVisits.SUBJECT,
                        String.format(ZoneConstants.DocVisits.SUBJECT_DESC_TEMPLATE, ctx.getSubjectDesc(), totalVisits), null);

                zonePointsDocMapper.incrementTriggerCount(pointsDoc.getId(), 1);
            }
        }
    }
}
