package com.atlassian.stash.internal.maintenance.backup;

import com.atlassian.bitbucket.Product;
import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.util.Progress;
import com.atlassian.bitbucket.util.ProgressImpl;
import com.atlassian.stash.internal.maintenance.AbstractMaintenanceTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.util.concurrent.CountDownLatch;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * Placeholder step in the overall backup process that ensures that the server side backup code waits for the
 * external backup client to perform whatever operations it needs to do. This placeholder step blocks the
 * {@link BackupTask} until the client has indicated that it has completed
 * (through {@link com.atlassian.stash.internal.backup.BackupService#updateClientProgress(int)}).
 */
public class BackupClientPlaceholderStep extends AbstractMaintenanceTask implements BackupClientProgressCallback {

    protected static final Logger log = LoggerFactory.getLogger(BackupClientPlaceholderStep.class);

    private final CountDownLatch latch;
    private final I18nService i18nService;

    private volatile int percentage;

    public BackupClientPlaceholderStep(I18nService i18nService) {
        this.i18nService = i18nService;
        this.latch = new CountDownLatch(1);
    }

    @Nonnull
    @Override
    public Progress getProgress() {
        return new ProgressImpl(i18nService.getMessage("bitbucket.backup.home.dir", Product.NAME), percentage);
    }

    @Override
    public void run() {
        try {
            log.debug("Waiting for client backup progress to reach 100. Current progress: {}", percentage);
            latch.await();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    @Override
    public void cancel() {
        super.cancel();
        latch.countDown();
    }

    @Override
    public void onProgressUpdate(int percentage) {
        checkArgument(percentage >= 0 && percentage <= 100, "percentage must between 0 and 100");
        checkArgument(percentage >= this.percentage,
                String.format("percentage must not decrease (previous value: %d)", percentage));

        log.debug("New progress update from backup client: {}", percentage);

        this.percentage = Math.min(100, percentage);

        if (percentage == 100) {
            latch.countDown();
        }
    }
}
