#!/usr/bin/env fish
# Copy local files/folders into Jellyfin's RWX PVC reliably using rsync.
# Primary path: NodePort -> rsync direct to node (no apiserver).
# Fallback: kubectl port-forward to service (OK for small/medium files).
#
# Usage:
#   scripts/ops/jellyfin_manual_load.fish <LOCAL_PATH> [REMOTE_SUBDIR] [JELLYFIN_API_KEY]
# Examples:
#   scripts/ops/jellyfin_manual_load.fish "$HOME/Downloads/Avatar - The Last Airbender (2005 - 2008) [1080p]" kids_tv "$JELLYFIN_API_TOKEN"
#   scripts/ops/jellyfin_manual_load.fish "$HOME/Movies/." movies   # copy contents-only into /media/movies

function usage
  echo "Usage: "(basename (status filename))" <LOCAL_PATH> [REMOTE_SUBDIR] [JELLYFIN_API_KEY]"
  echo "  LOCAL_PATH: file or directory. Use '/.' to copy contents-only."
  echo "  REMOTE_SUBDIR: subdir under /media on the PVC (optional)."
end

# --- sanity checks ---
set -g KCTL (command -v kubectl)
if test -z "$KCTL"
  echo "ERROR: kubectl not found in PATH."; exit 1
end
if not command -sq rsync
  echo "ERROR: rsync not found. Install rsync and re-run."; exit 1
end

function kc --description 'kubectl with unlimited timeout'
  command "$KCTL" --request-timeout=0 $argv
end

# --- constants ---
set -g NS jellyfin
set -g POD loader
set -g CTN toolbox
set -g YAML services/jellyfin/loader.yaml
set -g RSYNC_SVC loader-rsync
set -g RSYNC_NODEPORT 30873
set -g DEST_BASE /media

# --- args ---
if test (count $argv) -lt 1
  usage; exit 1
end

# expand ~ in first arg even when quoted
set -l LOCAL_RAW $argv[1]
set -l LOCAL (string replace -r '^~(?=/|$)' -- $HOME $LOCAL_RAW)
if not test -e "$LOCAL"
  echo "ERROR: '$LOCAL' does not exist."; exit 1
end

set -l REMOTE_SUBDIR ""
if test (count $argv) -ge 2
  set REMOTE_SUBDIR (string replace -r '^/+|/+$' '' -- $argv[2])
end

set -l API_TOKEN ""
if test (count $argv) -ge 3
  set API_TOKEN $argv[3]
end

# contents-only mode if LOCAL ended with '/.'
set -l contents_only 0
if string match -r '/\.\s*$' -- "$LOCAL_RAW" >/dev/null
  set contents_only 1
  set LOCAL (string replace -r '/\.\s*$' '' -- "$LOCAL")
end

# --- create/refresh loader pod ---
if kc -n $NS get pod $POD -o name >/dev/null 2>&1
  echo "Found existing $NS/$POD; deleting it first..."
  kc -n $NS delete pod $POD --wait >/dev/null
end

echo "Creating $NS/$POD from $YAML ..."
if not kc -n $NS apply -f "$YAML" >/dev/null
  echo "ERROR: failed to apply $YAML"; exit 1
end

echo "Waiting for $NS/$POD to be Ready..."
if not kc -n $NS wait --for=condition=Ready pod/$POD --timeout=600s >/dev/null
  echo "ERROR: $POD did not become Ready."; exit 1
end

# ensure base dir & perms
kc -n $NS exec $POD -c $CTN -- sh -lc "mkdir -p -- \"$DEST_BASE\" && chmod 0777 \"$DEST_BASE\"" >/dev/null
if test -n "$REMOTE_SUBDIR"
  kc -n $NS exec $POD -c $CTN -- sh -lc "mkdir -p -- \"$DEST_BASE/$REMOTE_SUBDIR\" && chmod 0777 \"$DEST_BASE/$REMOTE_SUBDIR\"" >/dev/null
end

# label so a Service can select it
kc -n $NS label pod $POD app=loader --overwrite >/dev/null

# --- start rsync daemon inside the loader container ---
echo "Starting rsync daemon inside $NS/$POD ..."
set -l RSYNCD_CFG '
pid file = /var/run/rsyncd.pid
use chroot = no
log file = /dev/stdout
max connections = 4
[media]
  path = /media
  read only = false
  uid = 0
  gid = 0
  hosts allow = 0.0.0.0/0
'
# Install rsync (if needed), write config, stop any old rsync, then start daemon (detaches by itself).
if not kc -n $NS exec $POD -c $CTN -- sh -lc "
  (rsync --version >/dev/null 2>&1) || apk add --no-cache rsync >/dev/null 2>&1
  cat > /etc/rsyncd.conf <<'EOF'
$RSYNCD_CFG
EOF
  pkill rsync >/dev/null 2>&1 || true
  rsync --daemon --config=/etc/rsyncd.conf --port=873
  # quick presence check
  pgrep rsync >/dev/null
"
  echo "ERROR: failed to start rsyncd in the loader pod."; exit 1
end

# --- (re)create NodePort service to reach rsyncd ---
kc -n $NS delete svc $RSYNC_SVC --ignore-not-found >/dev/null
printf "%s\n" \
"apiVersion: v1
kind: Service
metadata:
  name: $RSYNC_SVC
  namespace: $NS
spec:
  type: NodePort
  selector:
    app: loader
  ports:
  - name: rsync
    port: 873
    targetPort: 873
    nodePort: $RSYNC_NODEPORT" | kc apply -f - >/dev/null

# wait for endpoints to be populated
for i in (seq 1 30)
  set -l ep (kc -n $NS get endpoints $RSYNC_SVC -o jsonpath='{range .subsets[*].addresses[*]}{.ip}{" "}{end}')
  if test -n "$ep"
    break
  end
  sleep 1
end

# Which node is the pod on?
set -l NODE (kc -n $NS get pod $POD -o jsonpath='{.spec.nodeName}')
set -l HOST (kc get node $NODE -o jsonpath='{range .status.addresses[?(@.type=="InternalIP")]}{.address}{end}')

# Try NodePort reachability; if blocked, fall back to port-forward.
set -l DEST_URL ""
set -l VIA "nodeport"
echo "Waiting for rsync on $HOST:$RSYNC_NODEPORT ..."
for i in (seq 1 10)
  if rsync "rsync://$HOST:$RSYNC_NODEPORT/" >/dev/null 2>&1
    set DEST_URL "rsync://$HOST:$RSYNC_NODEPORT/media"
    break
  end
  sleep 1
end

if test -z "$DEST_URL"
  set VIA "port-forward"
  set -l PF_LOCAL 3873
  echo "NodePort not reachable; falling back to kubectl port-forward on 127.0.0.1:$PF_LOCAL ..."
  # background port-forward; capture PID
  kc -n $NS port-forward svc/$RSYNC_SVC 127.0.0.1:$PF_LOCAL:873 >/dev/null 2>&1 &
  set -l PF_PID $last_pid

  # wait until local rsync answers
  for i in (seq 1 30)
    if rsync "rsync://127.0.0.1:$PF_LOCAL/" >/dev/null 2>&1
      set DEST_URL "rsync://127.0.0.1:$PF_LOCAL/media"
      break
    end
    sleep 1
  end

  if test -z "$DEST_URL"
    echo "ERROR: rsync daemon not reachable via NodePort or port-forward."
    if test -n "$PF_PID"
      command kill $PF_PID >/dev/null 2>&1
    end
    exit 1
  end
end

if test -n "$REMOTE_SUBDIR"
  set DEST_URL "$DEST_URL/$REMOTE_SUBDIR"
end

# --- rsync flags (robust/resumable/overwrite) ---
set -l RSYNC_FLAGS -a --progress --human-readable \
  --partial --partial-dir=.rsync-partial --delay-updates \
  --chmod=Du=rwx,Dgo=rwx,Fu=rw,Fgo=rw \
  --timeout=600 --contimeout=30 \
  --exclude='.nfs*'

# --- perform copy ---
set -l copy_ok 0
if test -f "$LOCAL"
  set -l base (basename "$LOCAL")
  echo "Copying file '$base' -> $DEST_URL/ ... ($VIA)"
  if rsync $RSYNC_FLAGS "$LOCAL" "$DEST_URL/"
    set copy_ok 1
  end
else if test -d "$LOCAL"
  set -l base (basename "$LOCAL")
  if test $contents_only -eq 1
    echo "Copying contents of '$base/' -> $DEST_URL/ ... ($VIA)"
    if rsync $RSYNC_FLAGS "$LOCAL/." "$DEST_URL/"
      set copy_ok 1
    end
  else
    echo "Copying folder '$base' -> $DEST_URL/ ... ($VIA)"
    if rsync $RSYNC_FLAGS "$LOCAL" "$DEST_URL/"
      set copy_ok 1
    end
  end
else
  echo "ERROR: '$LOCAL' is neither file nor directory."
end

# --- verify & optionally refresh Jellyfin ---
echo "Verifying on the pod (top level of "(test -n "$REMOTE_SUBDIR"; and echo "$DEST_BASE/$REMOTE_SUBDIR"; or echo "$DEST_BASE")") ..."
kc -n $NS exec $POD -c $CTN -- sh -lc "du -sh -- \"$DEST_BASE\"; ls -lah -- \"$DEST_BASE\" | sed -n '1,200p'"

if test $copy_ok -eq 1
  if test -n "$API_TOKEN"
    if command -sq curl
      echo "Triggering Jellyfin library refresh..."
      if curl -fsS -X POST -H "X-Emby-Token: $API_TOKEN" "https://stream.bstein.dev/Library/Refresh" >/dev/null
        echo "Jellyfin library refresh triggered."
      else
        echo "WARNING: Jellyfin library refresh HTTP call failed."
      end
    else
      echo "NOTE: 'curl' not found; skipping library refresh."
    end
  end

  echo "Cleaning up $NS/$POD and $RSYNC_SVC ..."
  if test "$VIA" = "port-forward" -a -n "$PF_PID"
    command kill $PF_PID >/dev/null 2>&1
  end
  kc -n $NS delete svc/$RSYNC_SVC --wait=false >/dev/null
  kc -n $NS delete pod/$POD --wait >/dev/null
  echo "Done."
else
  echo "Copy encountered errors; leaving $POD and $RSYNC_SVC running for inspection."
  echo "Tip: check rsyncd in the pod:  kubectl -n $NS exec $POD -c $CTN -- pgrep -a rsync || true"
  exit 1
end
