package com.ruoyi.jarvis.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.jarvis.config.TencentDocConfig;
import com.ruoyi.jarvis.service.ITencentDocTokenService;
import com.ruoyi.jarvis.util.TencentDocApiUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * 腾讯文档Token管理服务实现
 * 
 * @author system
 */
@Service
public class TencentDocTokenServiceImpl implements ITencentDocTokenService {
    
    private static final Logger log = LoggerFactory.getLogger(TencentDocTokenServiceImpl.class);
    
    /** Redis key前缀 */
    private static final String TOKEN_KEY_PREFIX = "tendoc:token:";
    private static final String REFRESH_TOKEN_KEY_PREFIX = "tendoc:refresh_token:";
    private static final String TOKEN_EXPIRE_TIME_KEY_PREFIX = "tendoc:token_expire:";
    
    @Autowired
    private TencentDocConfig tencentDocConfig;
    
    @Autowired
    private RedisCache redisCache;
    
    @Override
    public String getValidAccessToken() {
        String tokenKey = TOKEN_KEY_PREFIX + tencentDocConfig.getAppId();
        
        // 从Redis获取缓存的token
        if (redisCache.hasKey(tokenKey)) {
            Object cachedToken = redisCache.getCacheObject(tokenKey);
            if (cachedToken != null) {
                String token = cachedToken.toString();
                
                // 检查token是否即将过期（提前5分钟刷新）
                String expireTimeKey = TOKEN_EXPIRE_TIME_KEY_PREFIX + tencentDocConfig.getAppId();
                if (redisCache.hasKey(expireTimeKey)) {
                    Object expireTimeObj = redisCache.getCacheObject(expireTimeKey);
                    if (expireTimeObj != null) {
                        Long expireTime = Long.valueOf(expireTimeObj.toString());
                        long currentTime = System.currentTimeMillis();
                        // 如果还有5分钟以上有效期，直接返回
                        if (expireTime > currentTime + 5 * 60 * 1000) {
                            log.debug("使用缓存的访问令牌");
                            return token;
                        }
                    }
                } else {
                    // 如果没有过期时间记录，直接使用（可能是旧数据）
                    return token;
                }
            }
        }
        
        // Token不存在或已过期，尝试刷新
        log.info("访问令牌不存在或已过期，尝试刷新...");
        return refreshAccessToken();
    }
    
    @Override
    public String refreshAccessToken() {
        try {
            String refreshTokenKey = REFRESH_TOKEN_KEY_PREFIX + tencentDocConfig.getAppId();
            
            // 先尝试使用refresh_token刷新
            if (redisCache.hasKey(refreshTokenKey)) {
                Object refreshTokenObj = redisCache.getCacheObject(refreshTokenKey);
                if (refreshTokenObj != null) {
                    String refreshToken = refreshTokenObj.toString();
                    try {
                        JSONObject tokenInfo = TencentDocApiUtil.refreshAccessToken(
                            tencentDocConfig.getAppId(),
                            tencentDocConfig.getAppSecret(),
                            refreshToken,
                            tencentDocConfig.getRefreshTokenUrl()
                        );
                        
                        if (tokenInfo != null && tokenInfo.containsKey("access_token")) {
                            String newAccessToken = tokenInfo.getString("access_token");
                            String newRefreshToken = tokenInfo.getString("refresh_token");
                            Integer expiresIn = tokenInfo.getIntValue("expires_in");
                            
                            // 保存新的token
                            saveToken(newAccessToken, newRefreshToken, expiresIn);
                            
                            log.info("成功刷新访问令牌");
                            return newAccessToken;
                        }
                    } catch (Exception e) {
                        log.warn("使用refresh_token刷新失败: {}", e.getMessage());
                        // refresh_token可能已过期，清除它
                        redisCache.deleteObject(refreshTokenKey);
                    }
                }
            }
            
            // 如果没有refresh_token或刷新失败，需要重新获取授权
            log.warn("无法自动刷新token，没有有效的refresh_token，需要重新授权");
            throw new RuntimeException("无法获取访问令牌，请先完成授权（访问 /jarvis/tendoc/authUrl 获取授权URL）");
            
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            log.error("刷新访问令牌失败", e);
            throw new RuntimeException("刷新访问令牌失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 保存token到Redis
     */
    private void saveToken(String accessToken, String refreshToken, Integer expiresIn) {
        String tokenKey = TOKEN_KEY_PREFIX + tencentDocConfig.getAppId();
        String refreshTokenKey = REFRESH_TOKEN_KEY_PREFIX + tencentDocConfig.getAppId();
        String expireTimeKey = TOKEN_EXPIRE_TIME_KEY_PREFIX + tencentDocConfig.getAppId();
        
        // 保存access_token（有效期比实际少5分钟，确保提前刷新）
        int cacheExpireTime = expiresIn != null ? expiresIn - 300 : 6900; // 默认2小时减5分钟
        redisCache.setCacheObject(tokenKey, accessToken, cacheExpireTime, TimeUnit.SECONDS);
        
        // 保存refresh_token（有效期30天）
        if (refreshToken != null) {
            redisCache.setCacheObject(refreshTokenKey, refreshToken, 30, TimeUnit.DAYS);
        }
        
        // 保存过期时间戳
        long expireTime = System.currentTimeMillis() + (expiresIn != null ? expiresIn * 1000L : 7200000L);
        redisCache.setCacheObject(expireTimeKey, expireTime, cacheExpireTime, TimeUnit.SECONDS);
        
        log.info("访问令牌已保存到缓存，有效期: {} 秒", expiresIn);
    }
    
    /**
     * 手动设置token（用于从外部获取的token）
     * 注意：此方法需要public，供控制器调用
     */
    public void setToken(String accessToken, String refreshToken, Integer expiresIn) {
        saveToken(accessToken, refreshToken, expiresIn);
        log.info("手动设置访问令牌成功");
    }
    
    @Override
    public void clearToken() {
        String tokenKey = TOKEN_KEY_PREFIX + tencentDocConfig.getAppId();
        String refreshTokenKey = REFRESH_TOKEN_KEY_PREFIX + tencentDocConfig.getAppId();
        String expireTimeKey = TOKEN_EXPIRE_TIME_KEY_PREFIX + tencentDocConfig.getAppId();
        
        redisCache.deleteObject(tokenKey);
        redisCache.deleteObject(refreshTokenKey);
        redisCache.deleteObject(expireTimeKey);
        
        log.info("已清除访问令牌缓存");
    }
}

