#!/usr/bin/env bash

# This script prepares for a release. Run it with the release version as the first argument and it
# will update version numbers, update the changelog, and update copyright year.

set -eu

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$SCRIPT_DIR"

REPO_ROOT=../../../

$REPO_ROOT/scripts/utils/commit-verification

source $REPO_ROOT/scripts/utils/log
source $REPO_ROOT/scripts/utils/print-and-run

for argument in "$@"; do
    case "$argument" in
        -*)
            log_error "Unknown option \"$argument\""
            exit 1
            ;;
        *)
            PRODUCT_VERSION="$argument"
            ;;
    esac
done

changes_path=$REPO_ROOT/desktop/packages/mullvad-vpn/changes.txt
changelog_path=$REPO_ROOT/CHANGELOG.md
product_version_path=$REPO_ROOT/dist-assets/desktop-product-version.txt
source_date_epoch_path=$REPO_ROOT/dist-assets/desktop-source-date-epoch.txt

function checks {
    if [[ -z ${PRODUCT_VERSION+x} ]]; then
        log_error "Please give the release version as an argument to this script."
        log_error "For example: '2018.1-beta3' for a beta release, or '2018.6' for a stable one."
        exit 1
    fi

    if [[ $(git status --porcelain) ]]; then
        log_error "Dirty working directory! Will not accept that for an official release."
        exit 1
    fi

    if [[ $(grep "CHANGE THIS BEFORE A RELEASE" $changes_path) != "" ]]; then
        log_error "It looks like you did not update $changes_path"
        exit 1
    fi
}

function check_changelog {
    previous_version=$(grep -oP '## \[\K[^\]]+' $changelog_path | head -2 | tail -1)

    log_header "Changelog since previous release"
    git --no-pager diff -U30 "$previous_version"..HEAD -- $changelog_path

    log_info "\nThe changelog should only contain changes in the \"Unreleased\" section, unless it's a correction of a previous message. If something is added to the section of an already published release, double check that the change was actually included in that release. Changes can be made in another terminal/editor while this script is waiting for input, press 'r' to reprint the new diff after making changes."
    read -r -n 1 -p "Does this look good? (y: yes, q: abort, r: reload): " response
    echo ""

    if [[ "$response" =~ ^[Yy]$ ]]; then
        return
    elif [[ "$response" =~ ^[QqAa]$ ]]; then
        log_info "Aborting"
        exit 1
    elif [[ "$response" =~ ^[Rr]$ ]]; then
        check_changelog
    else
        log_error "Invalid response"
        check_changelog
    fi
}

function update_copyright_year {
    $REPO_ROOT/scripts/update-copyright
    if [[ $(git status --porcelain) ]]; then
        print_and_run git commit -a -S -m "Update copyright year in project files and code"
    fi
}

function update_changelog {
    sed -i -e "/^## \[Unreleased\]/a \\\n\\n## \[$PRODUCT_VERSION\] - $(date +%F)" $changelog_path

    log_info "\nPaused after editing changelog. Make potential edits, then press any key to continue..."
    read -r -s -n 1

    print_and_run git commit -S -m "Update desktop app changelog with $PRODUCT_VERSION section" \
        $changelog_path
}

function update_product_version {
    echo "$PRODUCT_VERSION" > $product_version_path
    print_and_run git commit -S -m "Update desktop app version to $PRODUCT_VERSION" \
        $product_version_path
}

# The timestamp every build artifact of this release is stamped with, so that anyone rebuilding
# the release arrives at identical packages. Read by build.sh. Taken now rather than derived from
# the date in the changelog, since more than one release can be prepared in a day and each needs
# its own value.
function update_source_date_epoch {
    source_date_epoch=$(date +%s)
    # Time only moves forward, so a new value <= old value means something is wrong.
    # This check does not catch forward clock shifts.
    if [[ "$source_date_epoch" -le "$(cat $source_date_epoch_path)" ]]; then
        log_error "The clock of this machine is behind the timestamp of the previous release."
        exit 1
    fi
    echo "$source_date_epoch" > $source_date_epoch_path
    print_and_run git commit -S -m "Update desktop app source date epoch for $PRODUCT_VERSION" \
        $source_date_epoch_path
}

function commit_relay_list {
    print_and_run $REPO_ROOT/scripts/commit-relay-list "$PRODUCT_VERSION"
}

checks
check_changelog
update_changelog
update_copyright_year
update_product_version
update_source_date_epoch
commit_relay_list

log_success "\n================================================="
log_success "| DONE preparing for a release!                 |"
log_success "|    Now verify that everything looks correct   |"
log_success "|    and then create and push the tag by        |"
log_success "|    running:                                   |"
log_success "|    $ $(dirname "$0")/2-create-and-push-tag"
log_success "================================================="
