package org.wfc.omada.config;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import org.wfc.common.core.constant.SecurityConstants;
import org.wfc.common.redis.service.RedisService;
import org.wfc.omada.config.domain.vo.AuthorizeTokenVO;
import org.wfc.omada.config.domain.vo.OmadaResult;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @description: Feign 配置
 * @author: caiyuchao
 * @date: 2024-11-21
 */
@Configuration
public class FeignConfig implements RequestInterceptor {

    @Autowired
    private RedisService redisService;

    @Autowired
    private OmadaProperties omadaProperties;

    private static final String REDIS_ACCESS_TOKEN = "wfc-api-omada:access-token";
    private static final String REDIS_REFRESH_TOKEN = "wfc-api-omada:refresh-token";

    private static final String OMADACID = "omadacId";
    private static final String CLIENT_ID = "client_id";
    private static final String CLIENT_SECRET = "client_secret";
    private static final String GRANT_TYPE = "grant_type";
    private static final String REFRESH_TOKEN = "refresh_token";
    private static final String AUTHORIZATION = "Authorization";
    private static final String CLIENT_CREDENTIALS = "client_credentials";
    private static final String OPENAPI_AUTHORIZE_TOKEN_PATH = "/openapi/authorize/token";

    @Override
    public void apply(RequestTemplate requestTemplate) {
        // 获取redis中的访问令牌
        String cacheAccessToken = redisService.getCacheObject(REDIS_ACCESS_TOKEN);
        String authorization;
        if (StrUtil.isBlank(cacheAccessToken)) {
            // 访问令牌不存在获取redis中的刷新令牌
            String cacheRefreshToken = redisService.getCacheObject(REDIS_REFRESH_TOKEN);
            OmadaResult<AuthorizeTokenVO> omadaResult = callOmadaTokenAPI(cacheRefreshToken);
            if (omadaResult == null || omadaResult.getResult() == null) {
                // 获取失败重新调用获取访问令牌接口
                omadaResult = callOmadaTokenAPI(null);
                if (omadaResult == null || omadaResult.getResult() == null) {
                    return;
                }
            }
            String accessToken = omadaResult.getResult().getAccessToken();
            String refreshToken = omadaResult.getResult().getRefreshToken();
            authorization = SecurityConstants.PRE_ACCESS_TOKEN + accessToken;
            // 保存访问令牌和刷新令牌到redis中
            redisService.setCacheObject(REDIS_ACCESS_TOKEN, accessToken, 7000L, TimeUnit.SECONDS);
            redisService.setCacheObject(REDIS_REFRESH_TOKEN, refreshToken, 13L, TimeUnit.DAYS);
        } else {
            authorization = SecurityConstants.PRE_ACCESS_TOKEN + cacheAccessToken;
        }
        if (StrUtil.isNotBlank(authorization)) {
            // 更新最新的omadaUrl和omadacId
            requestTemplate.target(omadaProperties.getOmadaUrl());
            String path = requestTemplate.path();
            String uri = path.substring(path.indexOf("/openapi/v1/") + 12);
            String lastUri = uri.substring(uri.indexOf("/"));
            if (!uri.startsWith("msp")) {
                requestTemplate.uri("/openapi/v1/" + omadaProperties.getOmadacId() + lastUri);
            }

            // 添加授权请求头
            requestTemplate.header(AUTHORIZATION, authorization);
        }
    }

    private OmadaResult<AuthorizeTokenVO> callOmadaTokenAPI(String cacheRefreshToken) {
        // 构造请求参数query和body
        Map<String, String> body = new HashMap<>();
        body.put(CLIENT_ID, omadaProperties.getClientId());
        body.put(CLIENT_SECRET, omadaProperties.getClientSecret());
        LinkedMultiValueMap<String, String> query = new LinkedMultiValueMap<>();
        String url = omadaProperties.getOmadaUrl() + OPENAPI_AUTHORIZE_TOKEN_PATH;
        if (StrUtil.isBlank(cacheRefreshToken)) {
            // 获取访问令牌
            // 调用客户端认证模式获取access token
            body.put(OMADACID, omadaProperties.getOmadacId());
            query.add(GRANT_TYPE, CLIENT_CREDENTIALS);
        } else {
            // 刷新访问令牌
            query.add(GRANT_TYPE, REFRESH_TOKEN);
            query.add(REFRESH_TOKEN, cacheRefreshToken);
        }
        HttpEntity<String> request = new HttpEntity<>(JSON.toJSONString(body));
        String uriString = UriComponentsBuilder.fromHttpUrl(url).queryParams(query).build().toUriString();
        // 发送调用请求
        RestTemplate restTemplate = new RestTemplate(new RestTemplateConfig.HttpsClientRequestFactory());
        ResponseEntity<OmadaResult<AuthorizeTokenVO>> responseEntity = restTemplate.exchange(uriString, HttpMethod.POST,
                request, new ParameterizedTypeReference<OmadaResult<AuthorizeTokenVO>>() {
                });
        return responseEntity.getBody();
    }

}