package com.xindazhou.business.service.community.sensitive;

import com.xindazhou.business.controller.admin.community.sensitive.vo.SensitiveWordPageReqVO;
import com.xindazhou.business.controller.admin.community.sensitive.vo.SensitiveWordRespVO;
import com.xindazhou.business.controller.admin.community.sensitive.vo.SensitiveWordSaveReqVO;
import com.xindazhou.business.convert.community.sensitive.SensitiveWordConvert;
import com.xindazhou.business.dal.community.dataobject.sensitive.SensitiveWordDO;
import com.xindazhou.business.dal.community.mysql.sensitive.SensitiveWordMapper;
import com.xindazhou.framework.common.exception.util.ServiceExceptionUtil;
import com.xindazhou.framework.common.pojo.PageResult;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

import static com.xindazhou.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;

/**
 * 敏感词 Service 实现类
 *
 * @author xindazhou
 */
@Service("communitySensitiveWordServiceImpl")
@Validated
@Slf4j
public class SensitiveWordServiceImpl implements SensitiveWordService {

    @Resource
    private SensitiveWordMapper sensitiveWordMapper;

    // 敏感词缓存（禁用词）
    private final ConcurrentHashMap<String, Pattern> forbiddenWordPatterns = new ConcurrentHashMap<>();
    // 敏感词缓存（替换词）
    private final ConcurrentHashMap<String, String> replaceWordMap = new ConcurrentHashMap<>();

    @PostConstruct
    public void init() {
        refreshCache();
    }

    /**
     * 刷新敏感词缓存
     */
    public void refreshCache() {
        forbiddenWordPatterns.clear();
        replaceWordMap.clear();

        List<SensitiveWordDO> words = sensitiveWordMapper.selectListEnabled();
        for (SensitiveWordDO word : words) {
            if (word.getType() == 1) {
                // 禁用词：使用正则表达式匹配
                String pattern = word.getWord().replace("*", ".*");
                forbiddenWordPatterns.put(word.getWord(), Pattern.compile(pattern));
            } else if (word.getType() == 2) {
                // 替换词：直接替换
                replaceWordMap.put(word.getWord(), word.getReplaceWord() != null ? word.getReplaceWord() : "***");
            }
        }
        log.info("敏感词缓存已刷新，禁用词: {}, 替换词: {}", forbiddenWordPatterns.size(), replaceWordMap.size());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createSensitiveWord(SensitiveWordSaveReqVO createReqVO) {
        // 校验敏感词是否存在
        SensitiveWordDO existWord = sensitiveWordMapper.selectOne(
                new com.xindazhou.framework.mybatis.core.query.LambdaQueryWrapperX<SensitiveWordDO>()
                        .eq(SensitiveWordDO::getWord, createReqVO.getWord()));
        if (existWord != null) {
            throw ServiceExceptionUtil.exception(BAD_REQUEST, "敏感词已存在");
        }

        // 插入
        SensitiveWordDO word = SensitiveWordConvert.INSTANCE.convert(createReqVO);
        sensitiveWordMapper.insert(word);

        // 刷新缓存
        refreshCache();
        return word.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSensitiveWord(SensitiveWordSaveReqVO updateReqVO) {
        // 校验存在
        validateSensitiveWordExists(updateReqVO.getId());
        // 校验敏感词是否存在（排除自己）
        SensitiveWordDO existWord = sensitiveWordMapper.selectOne(
                new com.xindazhou.framework.mybatis.core.query.LambdaQueryWrapperX<SensitiveWordDO>()
                        .eq(SensitiveWordDO::getWord, updateReqVO.getWord())
                        .ne(SensitiveWordDO::getId, updateReqVO.getId()));
        if (existWord != null) {
            throw ServiceExceptionUtil.exception(BAD_REQUEST, "敏感词已存在");
        }

        // 更新
        SensitiveWordDO updateObj = SensitiveWordConvert.INSTANCE.convert(updateReqVO);
        sensitiveWordMapper.updateById(updateObj);

        // 刷新缓存
        refreshCache();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSensitiveWord(Long id) {
        // 校验存在
        validateSensitiveWordExists(id);
        // 删除
        sensitiveWordMapper.deleteById(id);

        // 刷新缓存
        refreshCache();
    }

    private SensitiveWordDO validateSensitiveWordExists(Long id) {
        SensitiveWordDO word = sensitiveWordMapper.selectById(id);
        if (word == null) {
            throw ServiceExceptionUtil.exception(BAD_REQUEST, "敏感词不存在");
        }
        return word;
    }

    @Override
    public SensitiveWordRespVO getSensitiveWord(Long id) {
        SensitiveWordDO word = validateSensitiveWordExists(id);
        return SensitiveWordConvert.INSTANCE.convert(word);
    }

    @Override
    public PageResult<SensitiveWordRespVO> getSensitiveWordPage(SensitiveWordPageReqVO pageReqVO) {
        com.xindazhou.framework.mybatis.core.query.LambdaQueryWrapperX<SensitiveWordDO> queryWrapper = new com.xindazhou.framework.mybatis.core.query.LambdaQueryWrapperX<SensitiveWordDO>()
                .likeIfPresent(SensitiveWordDO::getWord, pageReqVO.getWord())
                .eqIfPresent(SensitiveWordDO::getType, pageReqVO.getType())
                .eqIfPresent(SensitiveWordDO::getStatus, pageReqVO.getStatus())
                .orderByDesc(SensitiveWordDO::getId);
        PageResult<SensitiveWordDO> pageResult = sensitiveWordMapper.selectPage(pageReqVO, queryWrapper);
        return SensitiveWordConvert.INSTANCE.convertPage(pageResult);
    }

    @Override
    public String filterSensitiveWord(String text) {
        if (text == null || text.isEmpty()) {
            return text;
        }

        // 1. 检查禁用词
        for (Pattern pattern : forbiddenWordPatterns.values()) {
            if (pattern.matcher(text).find()) {
                return null; // 包含禁用词，返回null表示不允许
            }
        }

        // 2. 替换敏感词
        String result = text;
        for (java.util.Map.Entry<String, String> entry : replaceWordMap.entrySet()) {
            result = result.replace(entry.getKey(), entry.getValue());
        }

        return result;
    }

}

