package com.tzld.piaoquan.api.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.tzld.piaoquan.api.common.enums.contentplatform.ExternalChannelStatusEnum;
import com.tzld.piaoquan.api.dao.mapper.contentplatform.ExternalChannelMapper;
import com.tzld.piaoquan.api.model.po.contentplatform.ExternalChannel;
import com.tzld.piaoquan.api.model.po.contentplatform.ExternalChannelExample;
import com.tzld.piaoquan.api.model.vo.ExternalChannelVO;
import com.tzld.piaoquan.api.service.ExternalService;
import com.tzld.piaoquan.growth.common.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class ExternalServiceImpl implements ExternalService {

    @Autowired
    private ExternalChannelMapper externalChannelMapper;

    @Autowired
    private RedisUtils redisUtils;

    // 缓存key前缀
    private static final String CACHE_KEY_PREFIX = "external:channel:";
    // 执行完成记录的缓存时间
    private static final long PROCESSED_EXPIRE_TIME = 2L * 24 * 60 * 60;
    // 待执行/执行中记录的缓存时间
    private static final long PENDING_EXPIRE_TIME = 30L * 60;
    // 失败记录的缓存时间
    private static final long FAILED_EXPIRE_TIME = 6 * 60L * 60;
    // 未知渠道记录的缓存时间
    private static final long UNKNOWN_CHANNEL_EXPIRE_TIME = 6 * 60L * 60;
    // 空值缓存标记
    private static final String NULL_CACHE_VALUE = "NULL";
    // 失败状态缓存标记
    private static final String FAILED_CACHE_VALUE = "FAILED";
    // 未知渠道状态缓存标记
    private static final String UNKNOWN_CHANNEL_CACHE_VALUE = "UNKNOWN_CHANNEL";

    @Override
    public ExternalChannelVO getChannelByRootSourceId(String rootSourceId) {
        // 1. 先查缓存
        String cacheKey = CACHE_KEY_PREFIX + rootSourceId;
        String cacheValue = redisUtils.getString(cacheKey);
        if (cacheValue != null) {
            // 缓存命中，判断特殊状态标记
            if (NULL_CACHE_VALUE.equals(cacheValue)) {
                // 空值缓存，表示记录不存在但已插入待处理
                log.info("getChannelByRootSourceId 缓存命中空值, rootSourceId={}", rootSourceId);
                return null;
            }
            if (FAILED_CACHE_VALUE.equals(cacheValue)) {
                // 失败状态缓存
                log.info("getChannelByRootSourceId 缓存命中失败状态, rootSourceId={}", rootSourceId);
                return null;
            }
            if (UNKNOWN_CHANNEL_CACHE_VALUE.equals(cacheValue)) {
                // 未知渠道状态缓存
                log.info("getChannelByRootSourceId 缓存命中未知渠道状态, rootSourceId={}", rootSourceId);
                return null;
            }
            try {
                ExternalChannelVO vo = JSONObject.parseObject(cacheValue, ExternalChannelVO.class);
                log.info("getChannelByRootSourceId 缓存命中, rootSourceId={}", rootSourceId);
                return vo;
            } catch (Exception e) {
                log.error("缓存解析失败, rootSourceId={}", rootSourceId, e);
            }
        }

        // 2. 查询数据库
        ExternalChannelExample example = new ExternalChannelExample();
        example.createCriteria()
                .andRootSourceIdEqualTo(rootSourceId)
                .andIsDeleteEqualTo(0);
        List<ExternalChannel> list = externalChannelMapper.selectByExample(example);

        // 3. 有结果则处理
        if (!CollectionUtils.isEmpty(list)) {
            ExternalChannel record = list.get(0);
            Integer status = record.getStatus();

            // FAILED 和 UNKNOWN_CHANNEL 不返回具体对象，写入对应特殊标记
            if (ExternalChannelStatusEnum.FAILED.getVal().equals(status)) {
                redisUtils.setValueWithExpire(cacheKey, FAILED_CACHE_VALUE, FAILED_EXPIRE_TIME);
                log.info("getChannelByRootSourceId 写入失败状态缓存, rootSourceId={}, expireTime={}s",
                        rootSourceId, FAILED_EXPIRE_TIME);
                return null;
            }
            if (ExternalChannelStatusEnum.UNKNOWN_CHANNEL.getVal().equals(status)) {
                redisUtils.setValueWithExpire(cacheKey, UNKNOWN_CHANNEL_CACHE_VALUE, UNKNOWN_CHANNEL_EXPIRE_TIME);
                log.info("getChannelByRootSourceId 写入未知渠道状态缓存, rootSourceId={}, expireTime={}s",
                        rootSourceId, UNKNOWN_CHANNEL_EXPIRE_TIME);
                return null;
            }

            ExternalChannelVO vo = new ExternalChannelVO();
            BeanUtils.copyProperties(record, vo);

            // 根据状态设置不同的缓存时间
            long expireTime = ExternalChannelStatusEnum.PROCESSED.getVal().equals(status)
                    ? PROCESSED_EXPIRE_TIME : PENDING_EXPIRE_TIME;

            // 写入缓存
            redisUtils.setValueWithExpire(cacheKey, JSONObject.toJSONString(vo), expireTime);
            log.info("getChannelByRootSourceId 写入缓存, rootSourceId={}, status={}, expireTime={}s",
                    rootSourceId, status, expireTime);
            return vo;
        }

        // 4. 没有结果则插入待处理记录
        log.info("external_channel 未找到记录，插入待处理记录, rootSourceId={}", rootSourceId);
        ExternalChannel pendingRecord = new ExternalChannel();
        pendingRecord.setRootSourceId(rootSourceId);
        pendingRecord.setStatus(ExternalChannelStatusEnum.PENDING.getVal());
        pendingRecord.setIsDelete(0);
        pendingRecord.setCreateTime(new Date());
        pendingRecord.setUpdateTime(new Date());
        externalChannelMapper.insertSelective(pendingRecord);

        // 空值缓存，防止缓存穿透，缓存10分钟
        redisUtils.setValueWithExpire(cacheKey, NULL_CACHE_VALUE, PENDING_EXPIRE_TIME);
        log.info("getChannelByRootSourceId 写入空值缓存, rootSourceId={}, expireTime={}s",
                rootSourceId, PENDING_EXPIRE_TIME);

        return null;
    }
}
