package com.cool.store.config.rest;

import okhttp3.OkHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.*;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Author suzhuhong
 * @Date 2025/4/1 9:56
 * @Version 1.0
 */

@Configuration
public class OkHttpConfig {

    private static final String TRUSTED_DOMAIN = "zhengxinfood.com";
    private static final int CONNECT_TIMEOUT = 30;
    private static final int READ_TIMEOUT = 30;
    private static final int WRITE_TIMEOUT = 30;

    @Bean
    public OkHttpClient okHttpClient() {
        return createCustomTrustOkHttpClient(TRUSTED_DOMAIN);
    }

    private OkHttpClient createCustomTrustOkHttpClient(String trustedDomain) {
        try {
            // 获取系统默认TrustManager
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                    TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init((KeyStore) null);
            TrustManager[] defaultTrustManagers = trustManagerFactory.getTrustManagers();
            X509TrustManager defaultTrustManager = (X509TrustManager) defaultTrustManagers[0];

            // 创建自定义TrustManager
            X509TrustManager customTrustManager = new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                    defaultTrustManager.checkClientTrusted(chain, authType);
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                    try {
                        defaultTrustManager.checkServerTrusted(chain, authType);
                    } catch (CertificateException e) {
                        if (!isCertificateForDomain(chain[0], trustedDomain)) {
                            throw new CertificateException("证书不匹配目标域名: " + trustedDomain);
                        }
                    }
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return defaultTrustManager.getAcceptedIssuers();
                }
            };

            // 配置SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{customTrustManager}, new SecureRandom());

            return new OkHttpClient.Builder()
                    .sslSocketFactory(sslContext.getSocketFactory(), customTrustManager)
                    .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                    .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
                    .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
                    .build();
        } catch (Exception e) {
            throw new RuntimeException("创建OkHttpClient失败", e);
        }
    }

    private boolean isCertificateForDomain(X509Certificate certificate, String domain) {
        try {
            // 检查CN (Common Name)
            String principal = certificate.getSubjectX500Principal().getName();
            if (principal.contains("CN=" + domain) || principal.contains("CN=*." + domain)) {
                return true;
            }

            // 检查SAN (Subject Alternative Names)
            Collection<List<?>> sans = certificate.getSubjectAlternativeNames();
            if (sans != null) {
                for (List<?> san : sans) {
                    // 类型2是DNS名称
                    if (san.get(0).equals(2)) {
                        String sanValue = (String) san.get(1);
                        if (sanValue.equals(domain) || sanValue.endsWith("." + domain)) {
                            return true;
                        }
                    }
                }
            }
            return false;
        } catch (Exception e) {
            return false;
        }
    }
}