package com.atlassian.bitbucket.mesh;

import com.atlassian.bitbucket.mesh.layout.StorageLayout;
import com.google.common.annotations.VisibleForTesting;
import org.h2.mvstore.MVStoreTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;

import java.io.IOException;
import java.io.StringWriter;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

import static com.atlassian.bitbucket.mesh.MeshConstants.PROFILE_SIDECAR;
import static org.h2.engine.Constants.VERSION_MAJOR;
import static org.h2.engine.Constants.VERSION_MINOR;

/**
 * Resets the {@code mesh.mv.db} file in the sidecar, if it is not compatible with the current H2 driver version. This
 * class doesn't delete or modify the contents of the file, just renames it so that the driver creates a new
 * {@code mesh.mv.db} file.
 */
public class IncompatibleSidecarDatabaseResetter {

    @VisibleForTesting
    static final String LEGACY_DB_FILE = String.format("mesh-legacy-pre-%d-%d.mv.db", VERSION_MAJOR, VERSION_MINOR);

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

    private final boolean sidecar;
    private final StorageLayout storageLayout;

    public IncompatibleSidecarDatabaseResetter(Environment environment, StorageLayout storageLayout) {
        sidecar = environment.acceptsProfiles(Profiles.of(PROFILE_SIDECAR));
        this.storageLayout = storageLayout;
    }

    public void mayReset() {
        if (!sidecar) {
            return;
        }

        Path dbFile = storageLayout.getHomeDir().resolve("mesh.mv.db");
        Path legacyDbFile = dbFile.resolveSibling(LEGACY_DB_FILE);

        if (Files.exists(dbFile) && !Files.exists(legacyDbFile) && !isSupportedFormat(dbFile)) {
            try {
                Files.move(dbFile, legacyDbFile, StandardCopyOption.ATOMIC_MOVE);
                log.info("Renamed '{}' to '{}' because it is not compatible with the current " +
                        "H2 driver version", dbFile, legacyDbFile);
            } catch (IOException e) {
                log.error("Unable to rename the database file {} due to an error.", dbFile, e);
                throw new UncheckedIOException(e);
            }
        }
    }

    private static boolean isSupportedFormat(Path filePath) {
        return MVStoreTool.info(filePath.toString(), new StringWriter()) == null;
    }
}