package com.easyproject.service.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjectUtil;
import com.coze.openapi.client.auth.OAuthToken;
import com.coze.openapi.service.auth.JWTOAuthClient;
import com.coze.openapi.service.config.Consts;
import com.easyproject.common.config.CozeJwtConfig;
import com.easyproject.common.constant.CacheConstants;
import com.easyproject.common.core.redis.RedisCache;
import com.easyproject.service.domain.coze.CozeTokenSet;
import com.easyproject.service.service.ICozeJwtService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 方法说明: coze平台Oauth授权配置
 * @param
 * @return
 * @author java-101
 * @date 2025-04-29 23:46:37
 */
@Slf4j
@Service
public class CozeJwtServiceImpl implements ICozeJwtService {

    @Resource
    private CozeJwtConfig cozeJwtConfig;
    @Resource
    private RedisCache redisCache;
    @Resource
    public StringRedisTemplate stringRedisTemplate;

    /**
     * 方法说明: OAuth JWT 授权（开发者） 获取token
     * @param
     * @return
     * @author java-101
     * @date 2025-04-29 23:48:22
     */
    @Override
    public OAuthToken getAccessToken() {
        if (redisCache.hasKey(CacheConstants.COZE_ACCESS_TOKEN_KEY)) {
            return redisCache.getCacheObject(CacheConstants.COZE_ACCESS_TOKEN_KEY);
        }

        String lockKey = "get_access_token";
        String value = UUID.randomUUID().toString();
        Boolean lockAcquired = false;
        int maxRetries = 5; // 最大重试次数
        int retries = 0; // 当前重试次数
        if(!redisCache.hasKey(CacheConstants.COZE_ACCESS_TOKEN_KEY)){
            while (!lockAcquired && retries < maxRetries) {
                try {
                    // 尝试获取锁，最多等待 5 秒钟
                    lockAcquired = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, value, 5, TimeUnit.SECONDS);//60秒后自动解锁
                    if(lockAcquired){
                        log.info("获取锁成功");
                        try {
                            OAuthToken oAuthToken = getOAuthToken();
                            redisCache.setCacheObject(CacheConstants.COZE_ACCESS_TOKEN_KEY, oAuthToken, 60 * 14, TimeUnit.SECONDS);
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        } finally {
                            if (value.equals(stringRedisTemplate.opsForValue().get(lockKey))) {
                                //删除锁
                                stringRedisTemplate.delete(lockKey);
                                log.info("删除锁成功");
                            }
                        }
                    }else{
                        retries++;
                        Thread.sleep(3000);
                    }

                } catch (InterruptedException e) {
                    // 处理中断异常
                    e.printStackTrace();
                    // 尝试重新标记中断状态，并继续重试
                    Thread.currentThread().interrupt();
                }
            }
        }

        return redisCache.getCacheObject(CacheConstants.COZE_ACCESS_TOKEN_KEY);
    }

    /**
     * 方法说明: 获取扣子 授权TOKEN
     * @param
     * @return
     * @author java-101
     * @date 2025-04-30 00:16:09
     */
    public OAuthToken getOAuthToken() {
        String jwtOauthClientID = cozeJwtConfig.getClientId();
        String jwtOauthPrivateKey = getPrivateKey();
        String jwtOauthPublicKeyID = cozeJwtConfig.getJwtPublicKey();
        OAuthToken resp = null;
        try {
            JWTOAuthClient oauth = new JWTOAuthClient.JWTOAuthBuilder()
                            .clientID(jwtOauthClientID)
                            .privateKey(jwtOauthPrivateKey)
                            .publicKey(jwtOauthPublicKeyID)
                            .baseURL(Consts.COZE_CN_BASE_URL)
                            .jwtBuilder(new ExampleJWTBuilder())
                            .build();
            resp = oauth.getAccessToken();
            System.out.println("get coze oauth token：" + resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resp;
    }

    /**
     * 方法说明: 读取密钥
     * @param
     * @return
     * @author java-101
     * @date 2025-04-30 00:26:07
     */
    public static String getPrivateKey() {
        String pemContent = null;
        try {
            pemContent = ResourceUtil.readUtf8Str("private_key.pem");
        } catch (IORuntimeException e) {
            e.printStackTrace();
        }
        return pemContent;
    }

    /**
     * 方法说明: 查询系统token 使用JWT方式获取token（永久授权）
     * @param
     * @return
     * @author java-101
     * @date 2025-04-30 00:54:35
     */
    @Override
    public CozeTokenSet getCozeTokenSetForToken() {
        CozeTokenSet tokenSet = null;
        //使用JWT方式获取token（永久授权）
        OAuthToken oAuthToken = getAccessToken();
        if(ObjectUtil.isNotEmpty(oAuthToken)){
            tokenSet = new CozeTokenSet();
            tokenSet.setPersonToken(oAuthToken.getAccessToken());
        }
        return tokenSet;
    }
}
