#!/usr/bin/env bash
#
# Deploy the WooCommerce plugin to the WordPress.org SVN working copy.
#
# Usage:
#   ./scripts/deploy-svn.sh [VERSION] [options]
#
# Options:
#   -m, --message MSG   Commit message (default: "Release VERSION")
#   --dry-run           Preview rsync and SVN steps without making changes
#   --skip-update       Skip "svn update" before deploy
#   -h, --help          Show help
#
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SOURCE_DIR="${SOURCE_DIR:-$(cd "${SCRIPT_DIR}/.." && pwd)}"
SVN_DIR="${SVN_DIR:-/Users/beniamincosma/Development/Elrond/Twispay/xmoney-payments}"
SVN_USERNAME="${SVN_USERNAME:-xmoneypayments}"
SVN_TRUNK="${SVN_DIR}/trunk"
SVN_TAGS="${SVN_DIR}/tags"

PLUGIN_FILE="${SOURCE_DIR}/class-xmoney-payments.php"
README_FILE="${SOURCE_DIR}/readme.txt"
ENV_FILE="${SOURCE_DIR}/.env"

DRY_RUN=0
SKIP_UPDATE=0
VERSION=""
MESSAGE=""

usage() {
	cat <<EOF
Deploy xMoney Payments WooCommerce plugin to WordPress.org SVN.

Usage:
  $(basename "$0") [VERSION] [options]

Options:
  -m, --message MSG   Commit message (default: "Release VERSION")
  --dry-run           Preview rsync and SVN steps without making changes
  --skip-update       Skip "svn update" before deploy
  -h, --help          Show this help

Environment:
  SOURCE_DIR          Git repo root (default: parent of scripts/)
  SVN_DIR             SVN working copy root
  SVN_USERNAME        SVN username (default: xmoneypayments)
  SVN_PASSWORD        Password (prompted if unset and stdin is a TTY)

Examples:
  $(basename "$0")
  $(basename "$0") 1.0.2 -m "Release 1.0.2: bug fixes"
  $(basename "$0") --dry-run
EOF
}

log() {
	printf '%s\n' "$*" >&2
}

die() {
	log "Error: $*"
	exit 1
}

require_cmd() {
	command -v "$1" >/dev/null 2>&1 || die "Required command not found: $1"
}

parse_version_from_plugin() {
	grep -m1 '^[[:space:]]*\*[[:space:]]*Version:' "${PLUGIN_FILE}" \
		| sed -E 's/^[[:space:]]*\*[[:space:]]*Version:[[:space:]]*//' \
		| tr -d '\r'
}

parse_version_from_readme() {
	grep -m1 '^Stable tag:' "${README_FILE}" \
		| sed -E 's/^Stable tag:[[:space:]]*//' \
		| tr -d '\r'
}

parse_version_from_constant() {
	grep -m1 "define( 'XMONEY_PAYMENTS_VERSION'" "${PLUGIN_FILE}" \
		| sed -E "s/.*'([^']+)'.*/\1/" \
		| tr -d '\r'
}

validate_version_format() {
	local ver="$1"
	[[ "${ver}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] \
		|| die "Invalid version format '${ver}' (expected X.Y.Z, no 'v' prefix)"
}

resolve_version() {
	local plugin_ver readme_ver constant_ver

	[[ -f "${PLUGIN_FILE}" ]] || die "Plugin file not found: ${PLUGIN_FILE}"
	[[ -f "${README_FILE}" ]] || die "Readme file not found: ${README_FILE}"

	plugin_ver="$(parse_version_from_plugin)"
	readme_ver="$(parse_version_from_readme)"
	constant_ver="$(parse_version_from_constant)"

	[[ -n "${plugin_ver}" ]] || die "Could not parse Version from ${PLUGIN_FILE}"
	[[ -n "${readme_ver}" ]] || die "Could not parse Stable tag from ${README_FILE}"
	[[ -n "${constant_ver}" ]] || die "Could not parse XMONEY_PAYMENTS_VERSION from ${PLUGIN_FILE}"

	if [[ "${plugin_ver}" != "${readme_ver}" ]]; then
		die "Version mismatch: plugin header (${plugin_ver}) vs readme Stable tag (${readme_ver})"
	fi

	if [[ "${plugin_ver}" != "${constant_ver}" ]]; then
		die "Version mismatch: plugin header (${plugin_ver}) vs XMONEY_PAYMENTS_VERSION (${constant_ver})"
	fi

	VERSION="${plugin_ver}"
	validate_version_format "${VERSION}"
}

load_env_file() {
	if [[ -f "${ENV_FILE}" ]]; then
		# shellcheck disable=SC1090
		set -a
		source "${ENV_FILE}"
		set +a
	fi
}

prompt_password() {
	if [[ -n "${SVN_PASSWORD:-}" ]]; then
		return 0
	fi

	if [[ -t 0 ]]; then
		printf 'SVN password for %s: ' "${SVN_USERNAME}" >&2
		read -rs SVN_PASSWORD
		printf '\n' >&2
		export SVN_PASSWORD
		[[ -n "${SVN_PASSWORD}" ]] || die "Empty SVN password"
		return 0
	fi

	load_env_file
	[[ -n "${SVN_PASSWORD:-}" ]] || die "SVN_PASSWORD not set (non-interactive). Set SVN_PASSWORD or create ${ENV_FILE}"
}

svn_cmd() {
	if [[ "${DRY_RUN}" -eq 1 ]]; then
		log "[dry-run] svn $*"
		return 0
	fi

	if [[ -n "${SVN_PASSWORD:-}" ]]; then
		svn --username "${SVN_USERNAME}" --password "${SVN_PASSWORD}" --no-auth-cache "$@"
	else
		svn --username "${SVN_USERNAME}" "$@"
	fi
}

rsync_to_trunk() {
	local rsync_args=(
		-a
		--delete
		--exclude='vendor/'
		--exclude='tests/'
		--exclude='.git/'
		--exclude='.svn/'
		--exclude='.DS_Store'
		--exclude='*.swp'
	)

	if [[ "${DRY_RUN}" -eq 1 ]]; then
		rsync_args+=(--dry-run -v)
		log "[dry-run] rsync ${rsync_args[*]} ${SOURCE_DIR}/ ${SVN_TRUNK}/"
	else
		log "Syncing ${SOURCE_DIR}/ -> ${SVN_TRUNK}/"
	fi

	rsync "${rsync_args[@]}" "${SOURCE_DIR}/" "${SVN_TRUNK}/"
}

tag_exists() {
	if [[ -d "${SVN_TAGS}/${VERSION}" ]]; then
		return 0
	fi

	if svn_cmd info "${SVN_TAGS}/${VERSION}" >/dev/null 2>&1; then
		return 0
	fi

	return 1
}

check_svn_layout() {
	[[ -d "${SVN_DIR}/.svn" ]] || die "Not an SVN working copy: ${SVN_DIR}"
	[[ -d "${SVN_TRUNK}" ]] || die "SVN trunk not found: ${SVN_TRUNK}"
	[[ -d "${SVN_TAGS}" ]] || die "SVN tags directory not found: ${SVN_TAGS}"
}

show_svn_status() {
	log ""
	log "SVN status:"
	svn_cmd status "${SVN_DIR}" || true
}

deploy_svn() {
	cd "${SVN_DIR}"

	if [[ "${SKIP_UPDATE}" -eq 0 ]]; then
		log "Updating SVN working copy..."
		svn_cmd update
	fi

	if tag_exists; then
		die "Tag already exists: tags/${VERSION}"
	fi

	log "Adding new/changed files under trunk..."
	svn_cmd add --force trunk

	log "Creating tag tags/${VERSION} from trunk..."
	svn_cmd copy trunk "tags/${VERSION}"

	show_svn_status

	if [[ -z "${MESSAGE}" ]]; then
		MESSAGE="Release ${VERSION}"
	fi

	log ""
	log "Committing with message: ${MESSAGE}"
	svn_cmd commit -m "${MESSAGE}" .
}

parse_args() {
	while [[ $# -gt 0 ]]; do
		case "$1" in
			-h | --help)
				usage
				exit 0
				;;
			--dry-run)
				DRY_RUN=1
				shift
				;;
			--skip-update)
				SKIP_UPDATE=1
				shift
				;;
			-m | --message)
				[[ $# -ge 2 ]] || die "Option ${1} requires an argument"
				MESSAGE="$2"
				shift 2
				;;
			-*)
				die "Unknown option: $1"
				;;
			*)
				if [[ -z "${VERSION}" ]]; then
					VERSION="$1"
					validate_version_format "${VERSION}"
				else
					die "Unexpected argument: $1"
				fi
				shift
				;;
		esac
	done
}

main() {
	parse_args "$@"

	require_cmd svn
	require_cmd rsync
	require_cmd grep
	require_cmd sed

	check_svn_layout

	if [[ -z "${VERSION}" ]]; then
		resolve_version
		log "Detected version: ${VERSION}"
	else
		log "Using version from argument: ${VERSION}"
	fi

	if [[ "${DRY_RUN}" -eq 1 ]]; then
		log "Dry-run mode enabled (no writes or commits)."
	fi

	rsync_to_trunk

	if [[ "${DRY_RUN}" -eq 1 ]]; then
		log ""
		log "Planned SVN steps:"
		log "  svn update (unless --skip-update)"
		log "  svn add --force trunk"
		log "  svn copy trunk tags/${VERSION}"
		log "  svn commit -m \"${MESSAGE:-Release ${VERSION}}\" ."
		exit 0
	fi

	prompt_password
	deploy_svn

	log ""
	log "Deploy complete: version ${VERSION} -> tags/${VERSION}"
}

main "$@"
