#!/usr/bin/env bash
#
# AggroCycling Zwift Launcher Script (macOS / Linux)
# Locates Zwift workout folder, downloads all workouts from the API, and launches Zwift.
#
# Usage:
#   ./AggroCycling_ZwiftLauncher.sh
#   ./AggroCycling_ZwiftLauncher.sh http://localhost:5067
#   ./AggroCycling_ZwiftLauncher.sh https://localhost:7046 --insecure
#
# Notes:
# - Zwift workouts folder is expected at: ~/Documents/Zwift/Workouts/{YourZwiftId}
# - Requires: bash, curl, python3

set -euo pipefail
IFS=$'\n\t'

API_BASE_URL="http://zwift.aggrocycling.baltigo.com"
CURL_INSECURE_FLAG=""

print_help() {
  cat <<'EOF'
AggroCycling Zwift Launcher (macOS / Linux)

Downloads all workout files from the AggroCycling Zwift Helper API into your Zwift Workouts folder and launches Zwift.

Usage:
  ./AggroCycling_ZwiftLauncher.sh [apiBaseUrl] [--insecure]

Examples:
  ./AggroCycling_ZwiftLauncher.sh
  ./AggroCycling_ZwiftLauncher.sh http://localhost:5067
  ./AggroCycling_ZwiftLauncher.sh https://localhost:7046 --insecure

Options:
  --insecure  Allow invalid/self-signed TLS certs (useful for local https).
  -h, --help  Show this help.
EOF
}

if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
  print_help
  exit 0
fi

if [[ -n "${1:-}" && "${1:-}" != "--insecure" ]]; then
  API_BASE_URL="$1"
  shift
fi

if [[ "${1:-}" == "--insecure" ]]; then
  CURL_INSECURE_FLAG="--insecure"
  shift
fi

if [[ -n "${1:-}" ]]; then
  echo "ERROR: Unexpected argument: $1" >&2
  echo "" >&2
  print_help >&2
  exit 2
fi

# Enforce HTTPS: convert HTTP to HTTPS
if [[ "${API_BASE_URL}" =~ ^http:// ]]; then
  API_BASE_URL="${API_BASE_URL/http:\/\//https:\/\/}"
fi

ZWIFT_BASE="${HOME}/Documents/Zwift/Workouts"
if [[ ! -d "${ZWIFT_BASE}" ]]; then
  echo "ERROR: Zwift Workouts directory not found at: ${ZWIFT_BASE}" >&2
  echo "Please ensure Zwift is installed and you have a Workouts folder." >&2
  exit 1
fi

ZWIFT_FOLDER=""
while IFS= read -r -d '' dir; do
  base="$(basename "$dir")"
  if [[ "$base" =~ ^[0-9]+$ ]]; then
    ZWIFT_FOLDER="$dir"
    break
  fi
done < <(find "${ZWIFT_BASE}" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z)

if [[ -z "${ZWIFT_FOLDER}" ]]; then
  echo "ERROR: No Zwift user ID folder found in: ${ZWIFT_BASE}" >&2
  echo "Please ensure you have at least one workout folder with a numeric ID." >&2
  exit 1
fi

echo "Found Zwift workout folder: ${ZWIFT_FOLDER}"
echo "API Base URL: ${API_BASE_URL}"
echo ""

echo "Cleaning up old AggroCycling workouts..."
deleted_count=0
while IFS= read -r -d '' file; do
  rm -f "$file" && ((deleted_count++)) || true
done < <(find "${ZWIFT_FOLDER}" -maxdepth 1 -type f -name "aggroCycling_*" -print0 2>/dev/null || true)

if [[ ${deleted_count} -gt 0 ]]; then
  echo "Deleted ${deleted_count} old AggroCycling workout(s)."
else
  echo "No old AggroCycling workouts found to delete."
fi
echo ""

command -v curl >/dev/null 2>&1 || { echo "ERROR: curl not found." >&2; exit 1; }
command -v python3 >/dev/null 2>&1 || { echo "ERROR: python3 not found." >&2; exit 1; }

FILES_JSON="$(mktemp)"
cleanup() { rm -f "${FILES_JSON}"; }
trap cleanup EXIT

echo "Fetching workout list from API..."
if ! curl -fsS ${CURL_INSECURE_FLAG} "${API_BASE_URL}/api/files" -o "${FILES_JSON}"; then
  echo "ERROR: Failed to connect to API at ${API_BASE_URL}" >&2
  echo "Make sure the application is running and the API URL is correct." >&2
  exit 1
fi

FILES_TSV="$(
  python3 - <<'PY' "${FILES_JSON}"
import json
import sys

path = sys.argv[1]
with open(path, "r", encoding="utf-8") as f:
    data = json.load(f)

if not isinstance(data, list):
    raise SystemExit("Expected /api/files to return a JSON array")

for item in data:
    if not isinstance(item, dict):
        continue
    file_id = item.get("id")
    name = item.get("originalFileName")
    if not file_id or not name:
        continue
    # Tab-separated; safe for most filenames (including spaces).
    print(f"{file_id}\t{name}")
PY
)"

if [[ -z "${FILES_TSV}" ]]; then
  echo "No workouts found in the API."
  exit 0
fi

downloaded=0
failed=0

echo "Starting downloads..."
echo ""

while IFS=$'\t' read -r file_id original_name; do
  if [[ -z "${file_id}" || -z "${original_name}" ]]; then
    continue
  fi

target_path="${ZWIFT_FOLDER}/${original_name}"
tmp_path="${target_path}.download"

printf "Downloading: %s ... " "${original_name}"

set +e
curl -fsS ${CURL_INSECURE_FLAG} "${API_BASE_URL}/api/files/${file_id}" -o "${tmp_path}"
curl_exit=$?
set -e

if [[ ${curl_exit} -ne 0 ]]; then
  echo "FAILED (download error)"
  rm -f "${tmp_path}" || true
  ((failed++))
  continue
fi

if [[ ! -s "${tmp_path}" ]]; then
  echo "FAILED (empty file)"
  rm -f "${tmp_path}" || true
  ((failed++))
  continue
fi

mv -f "${tmp_path}" "${target_path}"
echo "OK"
((downloaded++))
done <<< "${FILES_TSV}"

echo ""
echo "Download complete!"
echo "  Downloaded: ${downloaded}"
if [[ ${failed} -gt 0 ]]; then
  echo "  Failed: ${failed}" >&2
fi

echo ""
echo "All workouts have been downloaded to: ${ZWIFT_FOLDER}"

# Launch Zwift after successful download
ZWIFT_APP="/Applications/Zwift.app"
if [[ -d "${ZWIFT_APP}" ]]; then
  echo ""
  echo "Starting Zwift..."
  open "${ZWIFT_APP}"
  exit 0
else
  echo ""
  echo "WARNING: Zwift not found at: ${ZWIFT_APP}"
  echo "Please start Zwift manually to see the updated workouts."
  exit 0
fi


