package com.atlassian.stash.internal.license;

import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.i18n.KeyedMessage;
import com.atlassian.stash.internal.config.Clock;
import com.atlassian.stash.internal.server.InternalApplicationPropertiesService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

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

@Component("gracePeriodHandler")
public class DefaultGracePeriodHandler implements GracePeriodHandler {

    static final long GRACE_PERIOD = TimeUnit.HOURS.toMillis(24);
    static final long ONE_HOUR = TimeUnit.HOURS.toMillis(1);

    private final InternalApplicationPropertiesService applicationPropertiesService;
    private final Clock clock;
    private final I18nService i18nService;

    @Autowired
    public DefaultGracePeriodHandler(InternalApplicationPropertiesService applicationPropertiesService, Clock clock,
                                     I18nService i18nService) {
        this.applicationPropertiesService = applicationPropertiesService;
        this.clock = clock;
        this.i18nService = i18nService;
    }

    @Override
    public boolean isActive() {
        return getPositiveRemainingGracePeriod().isPresent();
    }

    @Nonnull
    @Override
    public Optional<KeyedMessage> getMessage() {
        return getPositiveRemainingGracePeriod().map(this::getGracePeriodMessage);
    }

    @Nonnull
    @Override
    public Optional<Long> getStartTime() {
        return applicationPropertiesService.getGracePeriodStartTime();
    }

    @Override
    public void start() {
        if (!getStartTime().isPresent()) {
            updateGracePeriodStartTime(clock.utcMillis());
        }
    }

    @Override
    public void stop() {
        if (getRemainingGracePeriod().filter(remainingGracePeriod -> remainingGracePeriod <= 0).isPresent()) {
            resetGracePeriodStartTime();
        }
    }

    private KeyedMessage getGracePeriodMessage(long remainingGracePeriod) {
        if (remainingGracePeriod < ONE_HOUR) {
            return i18nService.createKeyedMessage("bitbucket.license.over.limit.grace.period.minutes",
                    MILLISECONDS.toMinutes(remainingGracePeriod));
        }

        return i18nService.createKeyedMessage("bitbucket.license.over.limit.grace.period.hours",
                MILLISECONDS.toHours(remainingGracePeriod));
    }

    private Optional<Long> getPositiveRemainingGracePeriod() {
        return getRemainingGracePeriod().filter(remainingGracePeriod -> remainingGracePeriod > 0);
    }

    private Optional<Long> getRemainingGracePeriod() {
        return getStartTime().map(startTime -> GRACE_PERIOD - (clock.utcMillis() - startTime));
    }

    private void resetGracePeriodStartTime() {
        applicationPropertiesService.setGracePeriodStartTime(null);
    }

    private void updateGracePeriodStartTime(long time) {
        applicationPropertiesService.setGracePeriodStartTime(time);
    }
}