#!/usr/bin/env bash
# english-lockdown-runner.sh — idempotent re-apply of the ARRFLIX English-only lockdown.
#
# See docs/20-english-only-lockdown.md for the full design, layer breakdown,
# and drift-check procedure. This script handles two of the three layers:
#
#   1. Server-wide: UICulture / PreferredMetadataLanguage / MetadataCountryCode
#      via POST /System/Configuration.
#   2. Per-user:    UICulture / AudioLanguagePreference / SubtitleLanguagePreference /
#      PlayDefaultAudioTrack via POST /Users/{id}/Configuration for every account.
#
# The third layer (web SPA shim — navigator.language override + language-switcher
# CSS hide) is served via the bind-mounted web-overrides/ tree; nothing for
# this script to push.
#
# Idempotent — running it twice produces the same end state. Each layer is
# read, merged with English defaults, and POSTed back. Skips writes when the
# server already matches.
#
# Usage:
#   JELLYFIN_API_TOKEN=<admin-token> ./english-lockdown-runner.sh
#
# Optional env:
#   JELLYFIN_URL   default https://arrflix.s8n.ru
#   DRY_RUN        default unset; set DRY_RUN=1 to print payloads without POSTing
#
# Exit codes:
#   0  every layer landed (or already correct)
#   1  at least one POST failed; check stderr/stdout for which surface
#   2  bad invocation (missing required env)
#
# Token rotation note: the API token has full admin scope. Use a dedicated
# token, not a personal-account session token, and rotate after offboarding
# any operator with shell access to the host running this script.

set -euo pipefail

JELLYFIN_URL="${JELLYFIN_URL:-https://arrflix.s8n.ru}"
JELLYFIN_API_TOKEN="${JELLYFIN_API_TOKEN:?set JELLYFIN_API_TOKEN=<admin-token>; aborting (see docs/20-english-only-lockdown.md)}"
DRY_RUN="${DRY_RUN:-}"

AUTH="MediaBrowser Token=$JELLYFIN_API_TOKEN"

# Server-wide targets
SERVER_UI_CULTURE="en-US"
SERVER_METADATA_LANG="en"
SERVER_METADATA_COUNTRY="US"

# Per-user targets
USER_UI_CULTURE="en-US"
USER_AUDIO_LANG="eng"
USER_SUBTITLE_LANG="eng"
USER_PLAY_DEFAULT_AUDIO="true"

FAIL_COUNT=0

# ---------------------------------------------------------------------------
# Layer 1: server-wide config
# ---------------------------------------------------------------------------
echo "[*] Layer 1: server-wide /System/Configuration"
SERVER_TMP_IN=$(mktemp)
SERVER_TMP_OUT=$(mktemp)
trap 'rm -f "$SERVER_TMP_IN" "$SERVER_TMP_OUT"' EXIT

curl -ks "$JELLYFIN_URL/System/Configuration" -H "Authorization: $AUTH" > "$SERVER_TMP_IN"

CURRENT_SERVER=$(python3 -c "
import json
with open('$SERVER_TMP_IN') as f: c = json.load(f)
print(f\"UICulture={c.get('UICulture','<absent>')} PreferredMetadataLanguage={c.get('PreferredMetadataLanguage','<absent>')} MetadataCountryCode={c.get('MetadataCountryCode','<absent>')}\")
")
echo "    before: $CURRENT_SERVER"

NEEDS_SERVER_WRITE=$(python3 -c "
import json
with open('$SERVER_TMP_IN') as f: c = json.load(f)
ok = (
    c.get('UICulture') == '$SERVER_UI_CULTURE'
    and c.get('PreferredMetadataLanguage') == '$SERVER_METADATA_LANG'
    and c.get('MetadataCountryCode') == '$SERVER_METADATA_COUNTRY'
)
print('0' if ok else '1')
")

if [[ "$NEEDS_SERVER_WRITE" == "0" ]]; then
  echo "    ok: server already pinned, skipping write"
else
  python3 - <<PYEOF > "$SERVER_TMP_OUT"
import json
with open("$SERVER_TMP_IN") as f: c = json.load(f)
c["UICulture"] = "$SERVER_UI_CULTURE"
c["PreferredMetadataLanguage"] = "$SERVER_METADATA_LANG"
c["MetadataCountryCode"] = "$SERVER_METADATA_COUNTRY"
print(json.dumps(c))
PYEOF

  if [[ -n "$DRY_RUN" ]]; then
    echo "    DRY_RUN: would POST $(wc -c < "$SERVER_TMP_OUT") bytes to /System/Configuration"
  else
    HTTP=$(curl -ks -X POST "$JELLYFIN_URL/System/Configuration" \
      -H "Authorization: $AUTH" \
      -H "Content-Type: application/json" \
      --data-binary @"$SERVER_TMP_OUT" -w "%{http_code}" -o /dev/null)
    if [[ "$HTTP" == "204" || "$HTTP" == "200" ]]; then
      echo "    after:  UICulture=$SERVER_UI_CULTURE PreferredMetadataLanguage=$SERVER_METADATA_LANG MetadataCountryCode=$SERVER_METADATA_COUNTRY (HTTP $HTTP)"
    else
      echo "    ERROR: POST /System/Configuration returned HTTP $HTTP" >&2
      FAIL_COUNT=$((FAIL_COUNT + 1))
    fi
  fi
fi

echo

# ---------------------------------------------------------------------------
# Layer 2: per-user config
# ---------------------------------------------------------------------------
echo "[*] Layer 2: per-user /Users/{id}/Configuration"
USERS_JSON=$(curl -ks "$JELLYFIN_URL/Users" -H "Authorization: $AUTH")
USER_COUNT=$(echo "$USERS_JSON" | python3 -c "import json,sys; print(len(json.load(sys.stdin)))")
echo "    $USER_COUNT users found."
echo

# Process-substitution to keep `set -e` semantics in the loop body.
while IFS=$'\t' read -r USER_ID USER_NAME OLD_UI OLD_AUDIO OLD_SUB OLD_PLAY; do
  TMP_IN=$(mktemp)
  TMP_OUT=$(mktemp)
  curl -ks "$JELLYFIN_URL/Users/$USER_ID" -H "Authorization: $AUTH" > "$TMP_IN"

  NEEDS_USER_WRITE=$(python3 -c "
import json
with open('$TMP_IN') as f: u = json.load(f)
c = u.get('Configuration', {})
ok = (
    c.get('UICulture') == '$USER_UI_CULTURE'
    and c.get('AudioLanguagePreference') == '$USER_AUDIO_LANG'
    and c.get('SubtitleLanguagePreference') == '$USER_SUBTITLE_LANG'
    and c.get('PlayDefaultAudioTrack') is True
)
print('0' if ok else '1')
")

  if [[ "$NEEDS_USER_WRITE" == "0" ]]; then
    echo "    [ok]    $USER_NAME ($USER_ID) — already pinned"
    rm -f "$TMP_IN" "$TMP_OUT"
    continue
  fi

  python3 - <<PYEOF > "$TMP_OUT"
import json
with open("$TMP_IN") as f: u = json.load(f)
c = u["Configuration"]
c["UICulture"] = "$USER_UI_CULTURE"
c["AudioLanguagePreference"] = "$USER_AUDIO_LANG"
c["SubtitleLanguagePreference"] = "$USER_SUBTITLE_LANG"
c["PlayDefaultAudioTrack"] = True
print(json.dumps(c))
PYEOF

  if [[ -n "$DRY_RUN" ]]; then
    echo "    [dry]   $USER_NAME ($USER_ID) — would POST $(wc -c < "$TMP_OUT") bytes"
  else
    HTTP=$(curl -ks -X POST "$JELLYFIN_URL/Users/$USER_ID/Configuration" \
      -H "Authorization: $AUTH" \
      -H "Content-Type: application/json" \
      --data-binary @"$TMP_OUT" -w "%{http_code}" -o /dev/null)
    if [[ "$HTTP" == "204" || "$HTTP" == "200" ]]; then
      echo "    [pin]   $USER_NAME ($USER_ID) — UICulture=$USER_UI_CULTURE Audio=$USER_AUDIO_LANG Sub=$USER_SUBTITLE_LANG PlayDefault=true (HTTP $HTTP)"
    else
      echo "    [FAIL]  $USER_NAME ($USER_ID) — HTTP $HTTP" >&2
      FAIL_COUNT=$((FAIL_COUNT + 1))
    fi
  fi
  rm -f "$TMP_IN" "$TMP_OUT"
done < <(echo "$USERS_JSON" | python3 -c "
import json, sys
for u in json.load(sys.stdin):
    c = u.get('Configuration', {})
    print('\t'.join([
        u['Id'],
        u['Name'],
        str(c.get('UICulture', '')),
        str(c.get('AudioLanguagePreference', '')),
        str(c.get('SubtitleLanguagePreference', '')),
        str(c.get('PlayDefaultAudioTrack', '')),
    ]))
")

echo

# ---------------------------------------------------------------------------
# Summary + exit
# ---------------------------------------------------------------------------
if [[ $FAIL_COUNT -eq 0 ]]; then
  echo "[*] Done. All layers pinned (or already correct). Drift-check commands"
  echo "    in docs/20-english-only-lockdown.md."
  exit 0
else
  echo "[!] Done with $FAIL_COUNT failure(s). Re-run after investigating;"
  echo "    drift-check commands in docs/20-english-only-lockdown.md." >&2
  exit 1
fi
