package com.atlassian.bitbucket.mesh.config;

import com.atlassian.util.profiling.ProfilerConfiguration;
import com.atlassian.util.profiling.Timers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.core.env.Environment;

import static java.util.concurrent.TimeUnit.MILLISECONDS;

public class DefaultProfilingConfig implements ProfilingConfig {

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

    private final Environment environment;

    private volatile Settings current;

    public DefaultProfilingConfig(Environment environment) {
        this.environment = environment;

        //Don't apply the settings initially because they're already applied on startup
        current = create();
    }

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

    @Override
    public int getMinFrameTime() {
        return current.minFrameTime;
    }

    @Override
    public int getMinTraceTime() {
        return current.minTraceTime;
    }

    @Override
    public int getMaxFrameNameLength() {
        return current.maxFrameNameLength;
    }

    void reload() {
        current = create();
        current.apply();
    }

    Settings create() {
        return Binder.get(environment).bindOrCreate("profiling", Settings.class);
    }

    private static class Settings {

        private final boolean enabled;
        private final int minFrameTime;
        private final int minTraceTime;
        private final int maxFrameNameLength;

        @ConstructorBinding
        public Settings(@DefaultValue("false") boolean enabled, @DefaultValue("1") int minFrameTime,
                        @DefaultValue("0") int minTraceTime, @DefaultValue("300") int maxFrameNameLength) {
            this.enabled = enabled;
            this.minFrameTime = minFrameTime;
            this.minTraceTime = minTraceTime;
            this.maxFrameNameLength = Math.max(150, maxFrameNameLength);
        }

        void apply() {
            //Automatically propagate the settings to profiling
            ProfilerConfiguration configuration = Timers.getConfiguration();
            boolean wasEnabled = configuration.isEnabled();

            configuration.setEnabled(enabled);
            configuration.setMinFrameTime(minFrameTime, MILLISECONDS);
            configuration.setMinTraceTime(minTraceTime, MILLISECONDS);
            configuration.setMaxFrameNameLength(maxFrameNameLength);
            if (enabled != wasEnabled) {
                log.info("Profiling has been {}", enabled ? "enabled" : "disabled");
            }
        }
    }
}
