package com.codebyte.api.config.ssl;

import java.security.cert.X509Certificate;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.Status;

/**
 * Reports days-to-expiry for each certificate in the served chain. Goes {@code DOWN} under 14 days
 * and {@code OUT_OF_SERVICE} under 30, so expiry is visible (and alertable) well before an outage.
 */
public class SslCertificateHealthIndicator implements HealthIndicator {

    static final long DOWN_THRESHOLD_DAYS = 14;
    static final long WARN_THRESHOLD_DAYS = 30;

    private final PemSslMaterial material;

    public SslCertificateHealthIndicator(PemSslMaterial material) {
        this.material = material;
    }

    @Override
    public Health health() {
        Instant now = Instant.now();
        long minDays = Long.MAX_VALUE;
        Map<String, Object> details = new LinkedHashMap<>();
        for (X509Certificate cert : material.chain()) {
            long days = ChronoUnit.DAYS.between(now, cert.getNotAfter().toInstant());
            minDays = Math.min(minDays, days);
            details.put(
                    cert.getSubjectX500Principal().getName(),
                    "notAfter=" + cert.getNotAfter() + ", daysToExpiry=" + days);
        }

        Status status;
        if (minDays < DOWN_THRESHOLD_DAYS) {
            status = Status.DOWN;
        } else if (minDays < WARN_THRESHOLD_DAYS) {
            status = Status.OUT_OF_SERVICE;
        } else {
            status = Status.UP;
        }
        return Health.status(status)
                .withDetail("minDaysToExpiry", minDays)
                .withDetails(details)
                .build();
    }
}
