package com.fs.xiaoshouyi;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class XiaoShouYiOAuthUtils {

    // 销售易认证服务器地址
    private static final String AUTH_URL = "https://login.xiaoshouyi.com/auc/oauth2/auth";
    private static final String TOKEN_URL = "https://login.xiaoshouyi.com/auc/oauth2/token";

    // 业务API基础地址
    private static String apiBaseUrl = "https://api.xiaoshouyi.com";

    private static final String CLIENT_ID = "3d03b17acc06116f274b0f61797fd3b3";
    private static final String CLIENT_SECRET = "68a5ee9a9544054b691e24186d158bb5";
    private static final String REDIRECT_URI = "http://n9d2e4bc.natappfree.cc/xiaoShouYi/auth/callback";

    // Token缓存
    private static volatile String accessToken;
    private static volatile String tokenType;
    private static volatile long expiresAt;  // 过期时间戳
    private static volatile String refreshToken;
    private static volatile long refreshTokenExpiresAt;

    private static final ReentrantLock lock = new ReentrantLock();

    /**
     * 生成授权URL（前端跳转用）
     */
    public static String buildAuthUrl() {
        return buildAuthUrl("offline");
    }

    /**
     * 生成授权URL
     * @param accessType online:不返回refresh_token, offline:返回refresh_token
     */
    public static String buildAuthUrl(String accessType) {
        try {
            StringBuilder url = new StringBuilder(AUTH_URL);
            url.append("?response_type=code")
                    .append("&client_id=").append(CLIENT_ID)
                    .append("&redirect_uri=").append(URLEncoder.encode(REDIRECT_URI, StandardCharsets.UTF_8.name()))
                    .append("&scope=all")
                    .append("&oauthType=standard");

            if (accessType != null && !accessType.isEmpty()) {
                url.append("&access_type=").append(accessType);
            }

            log.info("生成授权URL: {}", url);
            return url.toString();
        } catch (UnsupportedEncodingException e) {
            log.error("URL编码异常", e);
            return "";
        }
    }

    /**
     * 用授权码换取token
     */
    public static TokenResponse exchangeCodeForToken(String code) {
        log.info("开始用授权码换取token, code={}", code);

        String body = String.format(
                "grant_type=authorization_code&client_id=%s&client_secret=%s&redirect_uri=%s&code=%s",
                CLIENT_ID, CLIENT_SECRET, REDIRECT_URI, code
        );

        try (HttpResponse response = HttpRequest.post(TOKEN_URL)
                .header("Content-Type", "application/x-www-form-urlencoded")
                .body(body)
                .timeout(30000)
                .execute()) {

            String result = response.body();
            log.info("换取token响应: {}", result);

            if (response.getStatus() == 200) {
                return parseAndCacheToken(result);
            } else {
                log.error("换取token失败, 状态码: {}, 响应: {}", response.getStatus(), result);
                TokenResponse errorResp = new TokenResponse();
                errorResp.setSuccess(false);
                errorResp.setError("HTTP状态码: " + response.getStatus());
                return errorResp;
            }
        } catch (Exception e) {
            log.error("换取token异常", e);
            TokenResponse errorResp = new TokenResponse();
            errorResp.setSuccess(false);
            errorResp.setError(e.getMessage());
            return errorResp;
        }
    }

    /**
     * 刷新access_token
     */
    public static TokenResponse refreshAccessToken() {
        if (refreshToken == null) {
            log.error("refresh_token为空，无法刷新");
            TokenResponse errorResp = new TokenResponse();
            errorResp.setSuccess(false);
            errorResp.setError("refresh_token为空");
            return errorResp;
        }

        log.info("开始刷新access_token");

        String body = String.format(
                "grant_type=refresh_token&client_id=%s&client_secret=%s&refresh_token=%s",
                CLIENT_ID, CLIENT_SECRET, refreshToken
        );

        try (HttpResponse response = HttpRequest.post(TOKEN_URL)
                .header("Content-Type", "application/x-www-form-urlencoded")
                .body(body)
                .timeout(30000)
                .execute()) {

            String result = response.body();
            log.info("刷新token响应: {}", result);

            if (response.getStatus() == 200) {
                return parseAndCacheToken(result);
            } else {
                log.error("刷新token失败, 状态码: {}", response.getStatus());
                TokenResponse errorResp = new TokenResponse();
                errorResp.setSuccess(false);
                errorResp.setError("刷新失败");
                return errorResp;
            }
        } catch (Exception e) {
            log.error("刷新token异常", e);
            TokenResponse errorResp = new TokenResponse();
            errorResp.setSuccess(false);
            errorResp.setError(e.getMessage());
            return errorResp;
        }
    }

    /**
     * 解析token响应并缓存
     */
    private static TokenResponse parseAndCacheToken(String responseJson) {
        JSONObject json = JSONUtil.parseObj(responseJson);
        TokenResponse response = new TokenResponse();

        lock.lock();
        try {
            if (json.containsKey("access_token")) {
                accessToken = json.getStr("access_token");
                tokenType = json.getStr("token_type");
                Long expiresIn = json.getLong("expires_in");
                expiresAt = System.currentTimeMillis() + (expiresIn != null ? expiresIn * 1000 : 7200 * 1000);

                refreshToken = json.getStr("refresh_token");
                Long refreshExpiresIn = json.getLong("refresh_token_expires_in");

                //TODO: 不清楚给的是具体到多久过期还是说是给的
                if (refreshExpiresIn != null) {
                    refreshTokenExpiresAt = System.currentTimeMillis() + refreshExpiresIn * 1000;
                }

                // 更新业务API地址
                if (json.containsKey("instance_uri") && json.getStr("instance_uri") != null) {
                    String instanceUri = json.getStr("instance_uri");
                    if (!instanceUri.isEmpty()) {
                        apiBaseUrl = instanceUri;
                    }
                }

                response.setSuccess(true);
                response.setAccessToken(accessToken);
                response.setTokenType(tokenType);
                response.setExpiresIn(expiresIn);
                response.setRefreshToken(refreshToken);
                response.setInstanceUri(apiBaseUrl);

                log.info("Token缓存成功, access_token={}, 有效期至: {}, apiBaseUrl={}",
                        accessToken.substring(0, Math.min(20, accessToken.length())),
                        new java.util.Date(expiresAt), apiBaseUrl);
            } else {
                response.setSuccess(false);
                response.setError(json.getStr("error_description", json.getStr("error", "未知错误")));
                log.error("Token响应解析失败: {}", responseJson);
            }
        } finally {
            lock.unlock();
        }

        return response;
    }

    /**
     * 获取有效的access_token（自动刷新）
     */
    public static String getValidAccessToken() {
        // 检查缓存是否有效（提前5分钟刷新）
        if (accessToken != null && System.currentTimeMillis() < expiresAt - 300000) {
            return accessToken;
        }

        lock.lock();
        try {
            // 双重检查
            if (accessToken != null && System.currentTimeMillis() < expiresAt - 300000) {
                return accessToken;
            }

            // 尝试用refresh_token刷新
            if (refreshToken != null && System.currentTimeMillis() < refreshTokenExpiresAt) {
                log.info("access_token即将过期，使用refresh_token刷新");
                TokenResponse response = refreshAccessToken();
                if (response.isSuccess()) {
                    return accessToken;
                }
            }

            log.error("无法获取有效token，需要重新授权");
            return null;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 获取Authorization Header
     */
    public static String getAuthorizationHeader() {
        String token = getValidAccessToken();
        if (token == null) {
            return null;
        }
        String type = (tokenType != null && !tokenType.isEmpty()) ? tokenType : "Bearer";
        return type + " " + token;
    }

    /**
     * 获取业务API基础地址
     */
    public static String getApiBaseUrl() {
        return apiBaseUrl;
    }

    /**
     * 清除缓存（授权失败时调用）
     */
    public static void clearCache() {
        lock.lock();
        try {
            accessToken = null;
            refreshToken = null;
            tokenType = null;
            expiresAt = 0;
            refreshTokenExpiresAt = 0;
            log.info("Token缓存已清除");
        } finally {
            lock.unlock();
        }
    }


    @Data
    public static class TokenResponse {
        private boolean success;
        private String error;
        private String accessToken;
        private String tokenType;
        private Long expiresIn;
        private String refreshToken;
        private String instanceUri;
    }
}