package edu.whut.infrastructure.adapter.repository;

import edu.whut.domain.tag.adapter.repository.ITagRepository;
import edu.whut.domain.tag.model.entity.CrowdTagsJobEntity;
import edu.whut.infrastructure.dao.ICrowdTagsDao;
import edu.whut.infrastructure.dao.ICrowdTagsDetailDao;
import edu.whut.infrastructure.dao.ICrowdTagsJobDao;
import edu.whut.infrastructure.dao.po.CrowdTags;
import edu.whut.infrastructure.dao.po.CrowdTagsDetail;
import edu.whut.infrastructure.dao.po.CrowdTagsJob;
import edu.whut.infrastructure.redis.IRedisService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBitSet;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;

/**
 * 人群标签仓储
 */
@Repository
@RequiredArgsConstructor
@Slf4j
public class TagRepository implements ITagRepository {

    private final ICrowdTagsDao crowdTagsDao;

    private final ICrowdTagsDetailDao crowdTagsDetailDao;

    private final ICrowdTagsJobDao crowdTagsJobDao;

    private final IRedisService redisService;

    /**
     * 根据标签 + 批次号查询一次「人群标签批次任务」配置。
     * 1）入参由调度/业务服务提供；
     * 2）查询 crowd_tags_job 表，拿到统计区间、规则等信息；
     * 3）若数据库无记录则返回 null，调用方需自行判空。
     * @param tagId
     * @param batchId
     * @return
     */
    @Override
    public CrowdTagsJobEntity queryCrowdTagsJobEntity(String tagId, String batchId) {
        CrowdTagsJob crowdTagsJobReq = new CrowdTagsJob();
        crowdTagsJobReq.setTagId(tagId);
        crowdTagsJobReq.setBatchId(batchId);

        CrowdTagsJob crowdTagsJobRes = crowdTagsJobDao.queryCrowdTagsJob(crowdTagsJobReq);
        if (null == crowdTagsJobRes) return null;

        CrowdTagsJobEntity crowdTagsJobEntity = new CrowdTagsJobEntity();
        BeanUtils.copyProperties(crowdTagsJobRes, crowdTagsJobEntity);
        return crowdTagsJobEntity;
    }

    /**
     * 新增「标签 - 用户」关系。
     * 先向 crowd_tags_detail 表插入一条 (tagId, userId)；
     * 再把 userId 映射到位图索引并写入 Redis BitSet，便于高速判定某用户是否属于该标签；
     * 如果数据库已存在同样的唯一键，会捕获 {@link org.springframework.dao.DuplicateKeyException} 并忽略。
     * @param tagId
     * @param userId
     */
    @Override
    public void addCrowdTagsUserId(String tagId, String userId) {
        CrowdTagsDetail crowdTagsDetailReq = new CrowdTagsDetail();
        crowdTagsDetailReq.setTagId(tagId);
        crowdTagsDetailReq.setUserId(userId);

        try {
            crowdTagsDetailDao.addCrowdTagsUserId(crowdTagsDetailReq);
        } catch (DuplicateKeyException ignore) {
            log.info("用户id{}已在人群标签{}中",userId,tagId);
            // 忽略唯一索引冲突
        }
        // 获取BitSet
        RBitSet bitSet = redisService.getBitSet(tagId);
        bitSet.set(redisService.getIndexFromUserId(userId));
    }
    /**
     * 更新标签的统计量（例如已命中的用户总数）。
     * 一般在整批用户写入完毕后调用，把本次新增 count 累加到
     * crowd_tags.statistics 字段，便于后续做报表或曝光。
     * @param tagId 标签 ID
     * @param count 本次新增或回填的数量
     */
    @Override
    public void updateCrowdTagsStatistics(String tagId, int count) {
        CrowdTags crowdTagsReq = new CrowdTags();
        crowdTagsReq.setTagId(tagId);
        crowdTagsReq.setStatistics(count);

        crowdTagsDao.updateCrowdTagsStatistics(crowdTagsReq);
    }

}
