package com.atlassian.bitbucket.mesh.config;

import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.boot.convert.DurationUnit;
import org.springframework.core.env.Environment;

import javax.annotation.Nonnull;
import java.time.Duration;
import java.time.temporal.ChronoUnit;

class DefaultAuthenticationConfig implements AuthenticationConfig {

    private final Environment environment;

    private volatile Settings current;

    DefaultAuthenticationConfig(Environment environment) {
        this.environment = environment;

        reload();
    }

    @Nonnull
    @Override
    public Duration getAllowedClockSkew() {
        return current.allowedClockSkew;
    }

    @Nonnull
    @Override
    public Duration getExpiryInterval() {
        return current.expiryInterval;
    }

    @Nonnull
    @Override
    public Duration getFailureLogInterval() {
        return current.failureLogInterval;
    }

    @Nonnull
    @Override
    public Duration getKeyRequestInterval() {
        return current.keyRequestInterval;
    }

    @Override
    public boolean isEnabled() {
        return current.enabled;
    }

    @Override
    public boolean isExpiryEnabled() {
        return current.expiryEnabled;
    }

    void reload() {
        current = Binder.get(environment).bindOrCreate("authentication", Settings.class);
    }

    private static class Settings {

        final Duration allowedClockSkew;
        final boolean enabled;
        final boolean expiryEnabled;
        final Duration expiryInterval;
        final Duration failureLogInterval;
        final Duration keyRequestInterval;

        @ConstructorBinding
        public Settings(@DefaultValue("2m") @DurationUnit(ChronoUnit.SECONDS) Duration allowedClockSkew,
                        @DefaultValue("true") boolean enabled,
                        @DefaultValue("1m") @DurationUnit(ChronoUnit.SECONDS) Duration expiryInterval,
                        @DefaultValue("1m") @DurationUnit(ChronoUnit.SECONDS) Duration failureLogInterval,
                        @DefaultValue("1m") @DurationUnit(ChronoUnit.SECONDS) Duration keyRequestInterval) {
            this.allowedClockSkew = allowedClockSkew;
            this.enabled = enabled;
            this.expiryInterval = expiryInterval;
            this.failureLogInterval = failureLogInterval;
            this.keyRequestInterval = keyRequestInterval;

            //Evaluate this once, since it will be requested frequently
            expiryEnabled = !(expiryInterval.isNegative() || expiryInterval.isZero());
        }
    }
}
