package com.magistr.app.config.auth;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.util.HexFormat;
import java.util.Locale;
import java.util.Set;

@Component
@ConfigurationProperties(prefix = "app.jwt")
public class JwtProperties {

    private static final Set<String> LEGACY_INSECURE_SECRET_FINGERPRINTS = Set.of(
            "884e52f1fbb3b0caf409bc76a14ba8e601d6117be5a9188319f2e84f9e19a853",
            "54f5809ada311ba1e12146a14db39ede2082b6f73ca7749bae8cd8450726eaf9"
    );

    private static final Set<String> PLACEHOLDER_MARKERS = Set.of(
            "change-me",
            "change_this",
            "change-this",
            "dev-only",
            "placeholder",
            "replace-with",
            "replace_this",
            "replace-this"
    );

    private String secret;
    private Duration accessTtl = Duration.ofMinutes(15);
    private Duration refreshTtl = Duration.ofDays(7);
    private String refreshCookieName = "magistr_refresh";
    private boolean refreshCookieSecure = false;

    public String getSecret() {
        return secret;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }

    public Duration getAccessTtl() {
        return accessTtl;
    }

    public void setAccessTtl(Duration accessTtl) {
        this.accessTtl = accessTtl;
    }

    public Duration getRefreshTtl() {
        return refreshTtl;
    }

    public void setRefreshTtl(Duration refreshTtl) {
        this.refreshTtl = refreshTtl;
    }

    public String getRefreshCookieName() {
        return refreshCookieName;
    }

    public void setRefreshCookieName(String refreshCookieName) {
        this.refreshCookieName = refreshCookieName;
    }

    public boolean isRefreshCookieSecure() {
        return refreshCookieSecure;
    }

    public void setRefreshCookieSecure(boolean refreshCookieSecure) {
        this.refreshCookieSecure = refreshCookieSecure;
    }

    public byte[] secretBytes() {
        if (secret == null || secret.isBlank()) {
            throw new IllegalStateException("JWT_SECRET обязателен и не может быть пустым");
        }

        byte[] bytes = secret.getBytes(StandardCharsets.UTF_8);
        if (bytes.length < 32) {
            throw new IllegalStateException("JWT_SECRET должен быть не короче 32 байт");
        }

        String normalized = secret.toLowerCase(Locale.ROOT);
        if (PLACEHOLDER_MARKERS.stream().anyMatch(normalized::contains)
                || LEGACY_INSECURE_SECRET_FINGERPRINTS.contains(sha256(bytes))) {
            throw new IllegalStateException("JWT_SECRET содержит известное небезопасное или шаблонное значение");
        }
        return bytes;
    }

    public void validateForEnvironment(boolean production) {
        secretBytes();
        if (production && !refreshCookieSecure) {
            throw new IllegalStateException(
                    "В production-профиле JWT_REFRESH_COOKIE_SECURE должен иметь значение true"
            );
        }
    }

    private String sha256(byte[] value) {
        try {
            return HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(value));
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("В JVM недоступен алгоритм SHA-256", e);
        }
    }
}
