package com.magistr.app.config.tenant;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Map;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * Обновляет K8s ConfigMap tenants-config через Kubernetes REST API.
 *
 * Работает ТОЛЬКО внутри K8s пода (использует ServiceAccount token).
 * При запуске вне K8s (локальная разработка) — просто логирует предупреждение.
 */
@Service
public class ConfigMapUpdater {

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

    private static final String TOKEN_PATH = "/var/run/secrets/kubernetes.io/serviceaccount/token";
    private static final String NAMESPACE_PATH = "/var/run/secrets/kubernetes.io/serviceaccount/namespace";
    private static final String K8S_API_BASE = "https://kubernetes.default.svc";
    private static final String CONFIGMAP_NAME = "tenants-config";

    private final ObjectMapper objectMapper = new ObjectMapper();
    private final boolean runningInK8s;

    public ConfigMapUpdater() {
        this.runningInK8s = Files.exists(Path.of(TOKEN_PATH));
        if (!runningInK8s) {
            log.info("Приложение запущено вне K8s — обновление ConfigMap будет пропущено");
        }
    }

    /**
     * Обновляет ConfigMap tenants-config с новым списком тенантов.
     * @return true если обновление успешно (или мы не в K8s)
     */
    public boolean updateTenantsConfig(List<TenantConfig> tenants) {
        if (!runningInK8s) {
            log.warn("Приложение запущено вне K8s, пропускаем обновление ConfigMap");
            return true;
        }

        try {
            String token = Files.readString(Path.of(TOKEN_PATH)).trim();
            String namespace = Files.readString(Path.of(NAMESPACE_PATH)).trim();

            // Формируем JSON для тенантов
            String tenantsJson = objectMapper.writerWithDefaultPrettyPrinter()
                    .writeValueAsString(tenants);

            // Strategic merge patch для ConfigMap
            String patchBody = objectMapper.writeValueAsString(Map.of(
                "data", Map.of("tenants.json", tenantsJson)
            ));

            String url = String.format("%s/api/v1/namespaces/%s/configmaps/%s",
                    K8S_API_BASE, namespace, CONFIGMAP_NAME);

            // Создаём HttpClient с отключённой проверкой сертификатов
            // (внутри кластера используется self-signed CA)
            HttpClient client = createInsecureClient();

            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(url))
                    .header("Authorization", "Bearer " + token)
                    .header("Content-Type", "application/strategic-merge-patch+json")
                    .method("PATCH", HttpRequest.BodyPublishers.ofString(patchBody))
                    .build();

            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() == 200) {
                log.info("ConfigMap '{}' успешно обновлён, тенантов: {}", CONFIGMAP_NAME, tenants.size());
                return true;
            } else {
                log.error("Не удалось обновить ConfigMap: HTTP {} — {}", response.statusCode(), response.body());
                return false;
            }

        } catch (Exception e) {
            log.error("Ошибка при обновлении ConfigMap: {}", e.getMessage());
            return false;
        }
    }

    /**
     * Создаёт HttpClient, который доверяет self-signed сертификатам K8s API.
     */
    private HttpClient createInsecureClient() {
        try {
            TrustManager[] trustAll = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {}
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {}
                }
            };

            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAll, new SecureRandom());

            return HttpClient.newBuilder()
                    .sslContext(sslContext)
                    .build();
        } catch (Exception e) {
            log.warn("Не удалось создать клиент без проверки сертификата, используем стандартный: {}", e.getMessage());
            return HttpClient.newHttpClient();
        }
    }
}
