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 DefaultRepairConfig implements RepairConfig {

    private final Environment environment;

    private volatile Settings current;

    DefaultRepairConfig(Environment environment) {
        this.environment = environment;
        reload();
    }

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

    @Nonnull
    @Override
    public Backoff getBackoff() {
        return current.backoff;
    }

    @Override
    public int getMaxAttempts() {
        return current.maxAttempts;
    }

    @Override
    public int getThrottleLimit() {
        return current.throttleLimit;
    }

    @Nonnull
    @Override
    public Duration getThrottleTimeout() {
        return current.throttleTimeout;
    }

    @Nonnull
    @Override
    public Duration getTimeout() {
        return current.timeout;
    }

    @Override
    public int getUpdateRefBatchSize() {
        return current.updateRefBatchSize;
    }

    private static class Settings {

        final ExponentialBackoff backoff;
        final int maxAttempts;
        final int throttleLimit;
        final Duration throttleTimeout;
        final Duration timeout;
        final int updateRefBatchSize;

        @ConstructorBinding
        public Settings(@DefaultValue("10") int maxAttempts, @DefaultValue("10") int throttleLimit,
                        @DefaultValue("30s") @DurationUnit(ChronoUnit.SECONDS) Duration throttleTimeout,
                        @DefaultValue("24h") @DurationUnit(ChronoUnit.SECONDS) Duration timeoutExecution,
                        @DefaultValue("20000") int updateRefBatchSize, ExponentialBackoff backoff) {
            this.backoff = backoff;
            this.maxAttempts = maxAttempts;
            this.throttleLimit = throttleLimit;
            this.throttleTimeout = throttleTimeout;
            this.updateRefBatchSize = Math.max(1, updateRefBatchSize);

            timeout = timeoutExecution;
        }
    }
}
