#!/usr/bin/env bash
set -euo pipefail
source "$SHELLOPS_DIR/.envrc"
import "$SHELLOPS_DIR/lib/cargo/api.sh"
import "$SHELLOPS_DIR/lib/manifest.api.sh"

USAGE="$(cat <<EOF
Publishes Rust crate(s) to a registry. Automatically detects whether the
project is a single crate or a multi-member workspace and does the right thing.

For workspaces: validates internal dep versions, then runs
cargo publish --workspace (Cargo 1.90+). Already-published members are
excluded on retry. Idempotent — safe to re-run after partial failures.

Usage: action rust publish [options]

Options:
  --registry <name>           Target registry (default: crates-io)
  --dry-run                   Pass --dry-run to cargo publish
  --cargo-path <p>            Path to Cargo.toml (auto-detects workspace root)
  --confidence-gate <ch>      Always internal; also crates.io if version >= gate
  --internal-registry <name>  Forgejo registry name (default: internal)
  -h, --help                  Show this help text.
EOF
)"

ARG_REGISTRY=""
ARG_DRY_RUN=""
ARG_CARGO_PATH=""
ARG_CONFIDENCE_GATE=""
ARG_INTERNAL_REGISTRY=""

function main() {
  parse_args "$@"

  local metadata
  metadata="$(cargo_metadata "${ARG_CARGO_PATH:-}")"

  local publishable_members
  publishable_members="$(cargo_workspace_get_publishable_count "${ARG_CARGO_PATH:-}")"

  local version
  version="$(jq_get "$metadata" '.packages[0].version')"

  if [[ "$publishable_members" -le 1 ]]; then
    log "Single crate detected, publishing directly..."
    local flags=""
    [[ -n "$ARG_REGISTRY" ]] && flags="--registry $ARG_REGISTRY"
    [[ -n "$ARG_DRY_RUN" ]] && flags="$flags --dry-run"
    # shellcheck disable=SC2086
    cargo publish $flags ${ARG_CARGO_PATH:+--manifest-path "$ARG_CARGO_PATH"}
  else
    log "Workspace with $publishable_members publishable members detected"
    local ws_args=()
    [[ -n "$ARG_REGISTRY" ]] && ws_args+=(--registry "$ARG_REGISTRY")
    [[ -n "$ARG_DRY_RUN" ]] && ws_args+=(--dry-run)
    [[ -n "$ARG_CARGO_PATH" ]] && ws_args+=(--cargo-path "$ARG_CARGO_PATH")
    [[ -n "$ARG_CONFIDENCE_GATE" ]] && ws_args+=(--confidence-gate "$ARG_CONFIDENCE_GATE")
    [[ -n "$ARG_INTERNAL_REGISTRY" ]] && ws_args+=(--internal-registry "$ARG_INTERNAL_REGISTRY")
    cargo_workspace_publish "$version" "${ws_args[@]}"
  fi
}

function parse_args() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
      -h|--help) log "$USAGE" && exit 0 ;;
      --registry) ARG_REGISTRY="$2"; shift ;;
      --dry-run) ARG_DRY_RUN="true" ;;
      --cargo-path) ARG_CARGO_PATH="$2"; shift ;;
      --confidence-gate) ARG_CONFIDENCE_GATE="$2"; shift ;;
      --internal-registry) ARG_INTERNAL_REGISTRY="$2"; shift ;;
      -*)
        error "Unknown option: $1"
        log "$USAGE"
        exit 1
        ;;
    esac
    shift
  done
}

main "$@"
