package com.sino.mci.channel.wecom.support;

import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.time.Duration;

/**
 * 企业微信 CP access_token 缓存配置存储。
 *
 * <p>在 {@link WxCpDefaultConfigImpl} 的内存缓存基础上，增加 Redis 二级缓存。
 * 当 Spring 上下文中存在 {@link StringRedisTemplate} 时，token 会写入 Redis 并设置过期时间；
 * 否则退化为内存缓存。</p>
 */
public class WeComAccessTokenCache extends WxCpDefaultConfigImpl {

    private static final Logger log = LoggerFactory.getLogger(WeComAccessTokenCache.class);

    private static final String KEY_PREFIX = "wecom:cp:access_token:";

    private final String accessTokenKey;
    private final StringRedisTemplate redisTemplate;

    public WeComAccessTokenCache(String corpId, Integer agentId, String corpSecret,
                                 StringRedisTemplate redisTemplate) {
        this.accessTokenKey = KEY_PREFIX + corpId + ":" + agentId;
        this.redisTemplate = redisTemplate;
        this.setCorpId(corpId);
        this.setCorpSecret(corpSecret);
        this.setAgentId(agentId);
    }

    @Override
    public String getAccessToken() {
        if (redisTemplate != null) {
            try {
                String token = redisTemplate.opsForValue().get(accessTokenKey);
                if (token != null && !token.isBlank()) {
                    return token;
                }
            } catch (Exception e) {
                log.warn("[WeCom] 读取 Redis access_token 失败，退化到内存缓存", e);
            }
        }
        return super.getAccessToken();
    }

    @Override
    public boolean isAccessTokenExpired() {
        if (redisTemplate != null) {
            try {
                return !Boolean.TRUE.equals(redisTemplate.hasKey(accessTokenKey));
            } catch (Exception e) {
                log.warn("[WeCom] 检查 Redis access_token 过期状态失败，退化到内存缓存", e);
            }
        }
        return super.isAccessTokenExpired();
    }

    @Override
    public void expireAccessToken() {
        if (redisTemplate != null) {
            try {
                redisTemplate.delete(accessTokenKey);
            } catch (Exception e) {
                log.warn("[WeCom] 删除 Redis access_token 失败", e);
            }
        }
        super.expireAccessToken();
    }

    @Override
    public synchronized void updateAccessToken(WxAccessToken accessToken) {
        updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
    }

    @Override
    public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) {
        if (redisTemplate != null && accessToken != null) {
            try {
                long ttl = Math.max(expiresInSeconds - 200L, 1L);
                redisTemplate.opsForValue().set(accessTokenKey, accessToken, Duration.ofSeconds(ttl));
            } catch (Exception e) {
                log.warn("[WeCom] 写入 Redis access_token 失败", e);
            }
        }
        super.updateAccessToken(accessToken, expiresInSeconds);
    }
}
