package com.cameleer.server.app.security;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

/**
 * Provides trust-all TLS helpers for OIDC connections when
 * {@code CAMELEER_OIDC_TLS_SKIP_VERIFY=true}. Package-private — only used
 * by {@link OidcTokenExchanger} and {@link SecurityConfig}.
 */
final class InsecureTlsHelper {

    private static final Logger log = LoggerFactory.getLogger(InsecureTlsHelper.class);

    private static volatile SSLSocketFactory cachedFactory;
    private static final HostnameVerifier ACCEPT_ALL = (hostname, session) -> true;

    private InsecureTlsHelper() {}

    static SSLSocketFactory socketFactory() {
        if (cachedFactory == null) {
            synchronized (InsecureTlsHelper.class) {
                if (cachedFactory == null) {
                    try {
                        TrustManager[] trustAll = {new X509TrustManager() {
                            @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
                            @Override public void checkClientTrusted(X509Certificate[] certs, String authType) {}
                            @Override public void checkServerTrusted(X509Certificate[] certs, String authType) {}
                        }};
                        SSLContext ctx = SSLContext.getInstance("TLS");
                        ctx.init(null, trustAll, new SecureRandom());
                        cachedFactory = ctx.getSocketFactory();
                        log.warn("OIDC TLS certificate verification disabled (skip-verify) — do not use in production");
                    } catch (Exception e) {
                        throw new IllegalStateException("Failed to create trust-all SSLContext", e);
                    }
                }
            }
        }
        return cachedFactory;
    }

    static HostnameVerifier hostnameVerifier() {
        return ACCEPT_ALL;
    }

    /**
     * Opens an {@link InputStream} from the given URL, applying trust-all TLS
     * if the connection is HTTPS and {@code skipVerify} is true.
     * <p>
     * Handles redirects manually because Java's automatic redirect following
     * creates new connections that do NOT inherit custom SSLSocketFactory /
     * HostnameVerifier settings.
     */
    static InputStream openStream(URL url, boolean skipVerify) throws Exception {
        URL current = url;
        for (int i = 0; i < 5; i++) {
            HttpURLConnection conn = (HttpURLConnection) current.openConnection();
            if (skipVerify && conn instanceof HttpsURLConnection https) {
                https.setSSLSocketFactory(socketFactory());
                https.setHostnameVerifier(hostnameVerifier());
            }
            conn.setInstanceFollowRedirects(false);
            int code = conn.getResponseCode();
            if (code >= 300 && code < 400) {
                String location = conn.getHeaderField("Location");
                conn.disconnect();
                if (location == null) {
                    throw new java.io.IOException("Redirect with no Location header from " + current);
                }
                current = new URI(location).toURL();
                log.debug("Following OIDC redirect -> {}", current);
                continue;
            }
            return conn.getInputStream();
        }
        throw new java.io.IOException("Too many redirects from " + url);
    }
}
