package com.atlassian.bitbucket.mesh.app;

import com.atlassian.bitbucket.mesh.util.Version;

import javax.annotation.Nonnull;

import static java.util.Objects.requireNonNull;

public enum VersionUpdate {

    /**
     * The {@link Version#getMajor major version} has decreased.
     */
    MAJOR_DOWNGRADE(false),
    /**
     * The {@link Version#getMajor major version} has increased.
     */
    MAJOR_UPGRADE(true),
    /**
     * The {@link Version#getMajor major version}s are the same, but the minor or patch version has decreased.
     */
    MINOR_DOWNGRADE(false),
    /**
     * The {@link Version#getMajor major version}s are the same, but the minor or patch version has increased.
     */
    MINOR_UPGRADE(true),
    /**
     * The version is unchanged.
     */
    NONE(false);

    private final boolean upgrade;

    VersionUpdate(boolean upgrade) {
        this.upgrade = upgrade;
    }

    /**
     * Compares the two provided {@link Version version}s to detect whether an upgrade or downgrade has occurred
     * and, if so, whether it is major or minor.
     *
     * @param current  the version from the current application
     * @param previous the version from the previous application
     * @return the detected update, or {@link VersionUpdate#NONE NONE} if the version is unchanged
     */
    @Nonnull
    public static VersionUpdate of(@Nonnull Version current, @Nonnull Version previous) {
        int majorNow = requireNonNull(current, "current").getMajor();
        int majorThen = requireNonNull(previous, "previous").getMajor();
        if (majorNow > majorThen) {
            return MAJOR_UPGRADE;
        }
        if (majorNow < majorThen) {
            return MAJOR_DOWNGRADE;
        }

        //Major version hasn't changed, so look for minor changes (which includes patch version changes)
        int comparison = current.compareTo(previous);
        if (comparison == 0) {
            return NONE;
        }

        return comparison > 0 ? MINOR_UPGRADE : MINOR_DOWNGRADE;
    }

    /**
     * @return {@code true} for {@link #MAJOR_UPGRADE} and {@link #MINOR_UPGRADE}; otherwise, {@code false}
     */
    public boolean isUpgrade() {
        return upgrade;
    }
}
