#!/usr/bin/env bash
# Build and publish albus-cli from a clean, pushed commit.

set -Eeuo pipefail

script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
repo_root="$(cd -- "$script_dir/.." && pwd)"

usage() {
    cat >&2 <<EOF
usage: $0 [--dry-run] [--testpypi] [--non-interactive] <cli-version>

Build and publish albus-cli from a clean, pushed commit.

  --dry-run          Validate the complete release without uploading.
  --testpypi         Target TestPyPI instead of production PyPI.
  --non-interactive  Upload without the typed confirmation. Valid only in
                     GitHub Actions, where the release environment's required
                     reviewer approves the run instead.
EOF
}

dry_run=false
non_interactive=false
repository="pypi"

while [[ $# -gt 0 ]]; do
    case "$1" in
        --dry-run)
            dry_run=true
            shift
            ;;
        --testpypi)
            repository="testpypi"
            shift
            ;;
        --non-interactive)
            non_interactive=true
            shift
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        --*)
            echo "error: unknown option: $1" >&2
            usage
            exit 2
            ;;
        *)
            break
            ;;
    esac
done

if [[ $# -ne 1 ]]; then
    usage
    exit 2
fi

cli_version="$1"

# A confirmation a script can supply is a confirmation a script can hard-code,
# so the flag only means anything where an approval already gated the run. The
# check keeps the prompt from being skipped by habit locally; it is not a
# security boundary, since anyone holding UV_PUBLISH_TOKEN can already upload.
if [[ "$non_interactive" == true && "${GITHUB_ACTIONS:-}" != "true" ]]; then
    echo "error: --non-interactive is for GitHub Actions, where the release" \
        "environment's required reviewer is the confirmation" >&2
    exit 1
fi

for command in git uv; do
    if ! command -v "$command" >/dev/null 2>&1; then
        echo "error: required command not found: $command" >&2
        exit 1
    fi
done

cd "$repo_root"

# shellcheck source=tools/release_state.sh
source "$script_dir/release_state.sh"

require_release_state "$cli_version"

if [[ "$dry_run" == false && "$release_branch" != "master" ]]; then
    echo "error: uploads must run from the master branch" >&2
    exit 1
fi

./tools/check

rm -rf dist
uv build

wheel=(dist/*.whl)
sdist=(dist/*.tar.gz)
if [[ ${#wheel[@]} -ne 1 || ${#sdist[@]} -ne 1 ]]; then
    echo "error: expected exactly one wheel and one sdist in dist/" >&2
    ls -la dist >&2 || true
    exit 1
fi

wheel_name="$(basename "${wheel[0]}")"
case "$wheel_name" in
    *-py3-none-any.whl) ;;
    *)
        echo "error: wheel must be py3-none-any, got $wheel_name" >&2
        exit 1
        ;;
esac

echo "wheel: ${wheel[0]}"
echo "sdist: ${sdist[0]}"
shasum -a 256 "${wheel[0]}" "${sdist[0]}"

if [[ "$dry_run" == true ]]; then
    echo "dry-run: skipping upload"
    exit 0
fi

if [[ -z "${UV_PUBLISH_TOKEN:-}" ]]; then
    echo "error: UV_PUBLISH_TOKEN is not set" >&2
    exit 1
fi

publish_url="https://upload.pypi.org/legacy/"
repository_label="PyPI"
if [[ "$repository" == "testpypi" ]]; then
    publish_url="https://test.pypi.org/legacy/"
    repository_label="TestPyPI"
fi

if [[ "$non_interactive" == false ]]; then
    if [[ ! -t 0 ]]; then
        echo "error: publishing requires an interactive confirmation" >&2
        exit 1
    fi

    confirmation_prompt="publish $cli_version to $repository_label"
    read -r -p "Type '$confirmation_prompt' to continue: " confirmation
    if [[ "$confirmation" != "$confirmation_prompt" ]]; then
        echo "Publication cancelled." >&2
        exit 1
    fi
fi

# The token stays in the environment, where uv reads it: an argument is
# readable by any local process through the process table.
uv publish \
    --publish-url "$publish_url" \
    --trusted-publishing never \
    dist/*

echo "Published albus-cli==$cli_version to $repository_label"
