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

usage() {
  cat >&2 <<'USAGE'
Usage: download.sh <repo> <skill-path> [--force] [--dry-run]

  <repo>        owner/repo or https://github.com/owner/repo(.git)
  <skill-path>  path to the skill directory within the repo
  --force       overwrite an existing destination directory
  --dry-run     fetch the tarball and print what would be installed; do not
                create or modify any files on disk
USAGE
  exit 2
}

FORCE=0
DRY_RUN=0
ARGS=()
for arg in "$@"; do
  case "$arg" in
    --force) FORCE=1 ;;
    --dry-run) DRY_RUN=1 ;;
    -h|--help) usage ;;
    *) ARGS+=("$arg") ;;
  esac
done

[[ ${#ARGS[@]} -eq 2 ]] || usage
REPO="${ARGS[0]}"
SKILL_PATH="${ARGS[1]}"

case "$REPO" in
  https://github.com/*)   REPO_SLUG="${REPO#https://github.com/}" ;;
  http://github.com/*)    REPO_SLUG="${REPO#http://github.com/}" ;;
  git@github.com:*)       REPO_SLUG="${REPO#git@github.com:}" ;;
  ssh://git@github.com/*) REPO_SLUG="${REPO#ssh://git@github.com/}" ;;
  *)                      REPO_SLUG="$REPO" ;;
esac
REPO_SLUG="${REPO_SLUG%.git}"
REPO_SLUG="${REPO_SLUG%/}"

if [[ ! "$REPO_SLUG" =~ ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ ]]; then
  echo "error: <repo> must resolve to owner/repo using [A-Za-z0-9._-] (got '${REPO_SLUG}')" >&2
  exit 2
fi

SKILL_PATH="${SKILL_PATH#/}"
SKILL_PATH="${SKILL_PATH%/}"
[[ -n "$SKILL_PATH" ]] || { echo "error: <skill-path> cannot be empty" >&2; exit 2; }
case "$SKILL_PATH" in *..*) echo "error: <skill-path> must not contain '..'" >&2; exit 2 ;; esac
if [[ ! "$SKILL_PATH" =~ ^[A-Za-z0-9._/-]+$ ]]; then
  echo "error: <skill-path> must match [A-Za-z0-9._/-]+ (got '${SKILL_PATH}')" >&2
  exit 2
fi

for dep in curl tar; do
  command -v "$dep" >/dev/null 2>&1 || { echo "error: ${dep} is required but not found on PATH" >&2; exit 127; }
done

DEST_NAME="$(basename "$SKILL_PATH")"
DEST_DIR=".claude/skills/${DEST_NAME}"

DEST_STATUS=""
if [[ -e "$DEST_DIR" ]]; then
  if [[ $DRY_RUN -eq 1 ]]; then
    if [[ $FORCE -eq 1 ]]; then
      DEST_STATUS="exists; would overwrite (--force)"
    else
      DEST_STATUS="exists; actual install would fail without --force"
    fi
  elif [[ $FORCE -eq 1 ]]; then
    rm -rf "$DEST_DIR"
  else
    echo "error: ${DEST_DIR} already exists (pass --force to overwrite)" >&2
    exit 1
  fi
fi

TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT

TAR_URL="https://codeload.github.com/${REPO_SLUG}/tar.gz/HEAD"
TAR_FILE="${TMP_DIR}/repo.tar.gz"

if ! curl -fsSL --retry 2 "$TAR_URL" -o "$TAR_FILE"; then
  echo "error: failed to fetch ${TAR_URL}" >&2
  echo "       (private repo, wrong name, or codeload.github.com unreachable)" >&2
  exit 1
fi

FULL_LIST="${TMP_DIR}/all.txt"
tar -tzf "$TAR_FILE" > "$FULL_LIST"
PREFIX="$(awk -F/ 'NR==1{print $1; exit}' "$FULL_LIST")"
[[ -n "$PREFIX" ]] || { echo "error: downloaded tarball is empty" >&2; exit 1; }

MATCH_PREFIX="${PREFIX}/${SKILL_PATH}/"
MATCH_LIST="${TMP_DIR}/files.txt"
awk -v p="$MATCH_PREFIX" 'index($0, p) == 1 && substr($0, length($0)) != "/"' \
  "$FULL_LIST" > "$MATCH_LIST"

FILE_COUNT=$(wc -l < "$MATCH_LIST" | tr -d ' ')
if [[ "$FILE_COUNT" -eq 0 ]]; then
  echo "error: no files under '${SKILL_PATH}' in ${REPO_SLUG}" >&2
  exit 3
fi

if [[ $DRY_RUN -eq 1 ]]; then
  echo "dry run: would install ${FILE_COUNT} file(s) from ${REPO_SLUG}/${SKILL_PATH} -> ${DEST_DIR}"
  [[ -n "$DEST_STATUS" ]] && echo "note: destination ${DEST_STATUS}"
  while IFS= read -r full; do
    echo "  ${full#$MATCH_PREFIX}"
  done < "$MATCH_LIST"
  exit 0
fi

EXTRACT_DIR="${TMP_DIR}/extract"
mkdir -p "$EXTRACT_DIR"
if ! tar -xzf "$TAR_FILE" -C "$EXTRACT_DIR" --strip-components=1 "${MATCH_PREFIX%/}"; then
  echo "error: failed to extract ${MATCH_PREFIX} from tarball" >&2
  exit 1
fi

SRC="${EXTRACT_DIR}/${SKILL_PATH}"
[[ -d "$SRC" ]] || { echo "error: expected directory ${SRC} not found after extract" >&2; exit 1; }

mkdir -p "$(dirname "$DEST_DIR")"
mv "$SRC" "$DEST_DIR"

REPO_Q="${REPO_SLUG//\'/\'\\\'\'}"
PATH_Q="${SKILL_PATH//\'/\'\\\'\'}"
cat > "${DEST_DIR}/.local-skill.stamp" <<STAMP
# Generated by local-skill. Commit this file so 'update.sh' can refresh the skill.
repo='${REPO_Q}'
path='${PATH_Q}'
STAMP

echo "installed ${FILE_COUNT} file(s) from ${REPO_SLUG}/${SKILL_PATH} -> ${DEST_DIR}"
