#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PYPROJECT_PATH="${ROOT_DIR}/pyproject.toml"
DIST_DIR="${ROOT_DIR}/dist"

VERSION_BUMP="patch"
EXPLICIT_VERSION=""
TOKEN_FILE="pypi_token.txt"
REPOSITORY_URL=""
DRY_RUN="false"

usage() {
  cat <<'EOF'
Usage: ./publish_pypi.sh [options]

Automates PyPI release from this workspace:
1) update version in pyproject.toml
2) clear dist/
3) uv build
4) uv run twine check dist/*
5) uv run twine upload dist/*

Options:
  --version-bump {patch|minor|major|none}  Version bump strategy (default: patch)
  --version X.Y.Z                           Explicit version (overrides --version-bump)
  --token-file PATH                         Token file path (default: pypi_token.txt)
  --repository-url URL                      Optional custom repository URL
  --dry-run                                 Build/check only, skip upload
  -h, --help                                Show this help

Token lookup priority:
  1) TWINE_PASSWORD
  2) PYPI_API_TOKEN
  3) --token-file (default pypi_token.txt)
EOF
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --version-bump)
      VERSION_BUMP="${2:-}"; shift 2 ;;
    --version)
      EXPLICIT_VERSION="${2:-}"; shift 2 ;;
    --token-file)
      TOKEN_FILE="${2:-}"; shift 2 ;;
    --repository-url)
      REPOSITORY_URL="${2:-}"; shift 2 ;;
    --dry-run)
      DRY_RUN="true"; shift ;;
    -h|--help)
      usage; exit 0 ;;
    *)
      echo "ERROR: Unknown argument: $1" >&2
      usage
      exit 1 ;;
  esac
done

if [[ ! -f "${PYPROJECT_PATH}" ]]; then
  echo "ERROR: pyproject.toml not found at ${PYPROJECT_PATH}" >&2
  exit 1
fi

if [[ ! "${VERSION_BUMP}" =~ ^(patch|minor|major|none)$ ]]; then
  echo "ERROR: --version-bump must be one of patch|minor|major|none" >&2
  exit 1
fi

CURRENT_VERSION="$(python - <<'PY'
from pathlib import Path
import re
content = Path("pyproject.toml").read_text(encoding="utf-8")
m = re.search(r'^\s*version\s*=\s*"([^"]+)"\s*$', content, re.MULTILINE)
if not m:
    raise SystemExit("Could not find version in pyproject.toml")
print(m.group(1))
PY
)"

if [[ -n "${EXPLICIT_VERSION}" ]]; then
  NEXT_VERSION="${EXPLICIT_VERSION}"
else
  NEXT_VERSION="$(python - "${CURRENT_VERSION}" "${VERSION_BUMP}" <<'PY'
import sys
version = sys.argv[1]
bump = sys.argv[2]
parts = version.split(".")
if len(parts) != 3 or any(not p.isdigit() for p in parts):
    raise SystemExit(f"Version must be semantic X.Y.Z, got: {version}")
major, minor, patch = map(int, parts)
if bump == "major":
    print(f"{major + 1}.0.0")
elif bump == "minor":
    print(f"{major}.{minor + 1}.0")
elif bump == "patch":
    print(f"{major}.{minor}.{patch + 1}")
elif bump == "none":
    print(version)
else:
    raise SystemExit(f"Unsupported bump type: {bump}")
PY
)"
fi

if [[ "${NEXT_VERSION}" != "${CURRENT_VERSION}" ]]; then
  python - "${NEXT_VERSION}" <<'PY'
from pathlib import Path
import re
import sys
new_version = sys.argv[1]
path = Path("pyproject.toml")
content = path.read_text(encoding="utf-8")
updated, count = re.subn(
    r'^(\s*version\s*=\s*")([^"]+)("\s*)$',
    rf'\g<1>{new_version}\g<3>',
    content,
    count=1,
    flags=re.MULTILINE,
)
if count != 1:
    raise SystemExit("Failed to update version in pyproject.toml")
path.write_text(updated, encoding="utf-8")
PY
  echo "SUCCESS: Version updated ${CURRENT_VERSION} -> ${NEXT_VERSION}"
else
  echo "INFO: Version unchanged (${CURRENT_VERSION})"
fi

mkdir -p "${DIST_DIR}"
rm -rf "${DIST_DIR:?}/"*
echo "INFO: Cleared dist/"

cd "${ROOT_DIR}"
echo "INFO: Building package..."
uv build

if ! compgen -G "${DIST_DIR}/*" > /dev/null; then
  echo "ERROR: Build produced no artifacts in dist/" >&2
  exit 1
fi

echo "INFO: Checking package metadata..."
uv run twine check "${DIST_DIR}"/*

if [[ "${DRY_RUN}" == "true" ]]; then
  echo "SUCCESS: Dry run complete. Upload skipped."
  exit 0
fi

TOKEN="${TWINE_PASSWORD:-${PYPI_API_TOKEN:-}}"
TOKEN_PATH="${TOKEN_FILE}"
TOKEN_SOURCE=""
if [[ "${TOKEN_PATH}" != /* ]]; then
  TOKEN_PATH="${ROOT_DIR}/${TOKEN_PATH}"
fi

if [[ -z "${TOKEN}" ]]; then
  if [[ ! -f "${TOKEN_PATH}" ]]; then
    echo "ERROR: No token found. Set TWINE_PASSWORD/PYPI_API_TOKEN or create ${TOKEN_PATH}" >&2
    exit 1
  fi
  TOKEN="$(<"${TOKEN_PATH}")"
  TOKEN_SOURCE="file:${TOKEN_PATH}"
else
  if [[ -n "${TWINE_PASSWORD:-}" ]]; then
    TOKEN_SOURCE="env:TWINE_PASSWORD"
  else
    TOKEN_SOURCE="env:PYPI_API_TOKEN"
  fi
fi

if [[ -z "${TOKEN// }" ]]; then
  echo "ERROR: PyPI token is empty." >&2
  exit 1
fi

export TWINE_USERNAME="__token__"
export TWINE_PASSWORD="${TOKEN}"
echo "INFO: Using token from ${TOKEN_SOURCE}"

UPLOAD_CMD=(uv run twine upload --non-interactive)
if [[ -n "${REPOSITORY_URL}" ]]; then
  UPLOAD_CMD+=(--repository-url "${REPOSITORY_URL}")
fi
UPLOAD_CMD+=("${DIST_DIR}"/*)

echo "INFO: Uploading artifacts..."
"${UPLOAD_CMD[@]}"
echo "SUCCESS: Published tropiflo ${NEXT_VERSION}"
