#!/bin/bash
# Hotfix: announcements modal HTTP 500 on GET /api/v1/announcements/schedules
# - Graceful empty schedule list when sudo/scripts fail (PHP)
# - Use /usr/bin/python3 under sudo in announce-schedule.sh
# - Ensure announce-*.sh are executable and sudoers allow www-data
#
# Run as root on the AllStar node:
#   sudo bash /var/www/html/supermon-ng/scripts/hotfix-announcements-schedules.sh
#
# Optional: SUPERMON_DIR=/other/path sudo bash hotfix-announcements-schedules.sh

set -euo pipefail

SUPERMON_DIR="${SUPERMON_DIR:-${1:-/var/www/html/supermon-ng}}"
SERVICE_PHP="${SUPERMON_DIR}/src/Services/AnnouncementsService.php"
SCHEDULE_SH="${SUPERMON_DIR}/user_files/sbin/announce-schedule.sh"
SBIN_DIR="${SUPERMON_DIR}/user_files/sbin"
STAMP="$(date +%Y%m%d%H%M%S)"

if [[ "$(id -u)" -ne 0 ]]; then
    echo "Run as root: sudo bash $0" >&2
    exit 1
fi

if [[ ! -d "$SUPERMON_DIR" ]]; then
    echo "Supermon-ng not found at: $SUPERMON_DIR" >&2
    exit 1
fi

echo "=== Supermon-ng announcements schedules hotfix ==="
echo "Install path: $SUPERMON_DIR"
echo

backup() {
    local f="$1"
    if [[ -f "$f" ]]; then
        cp -a "$f" "${f}.bak.${STAMP}"
        echo "  backup: ${f}.bak.${STAMP}"
    fi
}

patch_php() {
  if [[ ! -f "$SERVICE_PHP" ]]; then
    echo "ERROR: missing $SERVICE_PHP (is announcements feature installed?)" >&2
    return 1
  fi

  if grep -q 'Could not list announcement schedules' "$SERVICE_PHP"; then
    echo "[PHP] Already patched — skipping"
    return 0
  fi

  echo "[PHP] Patching listSchedules() in AnnouncementsService.php"
  backup "$SERVICE_PHP"

  python3 - "$SERVICE_PHP" <<'PY'
import sys
from pathlib import Path

path = Path(sys.argv[1])
text = path.read_text()

old = """    public function listSchedules(): array
    {
        $json = $this->runSudoScriptCapture('announce-schedule.sh', ['list']);
        $decoded = json_decode($json, true);
        if (!is_array($decoded)) {
            return [];
        }

        return $decoded;
    }"""

new = """    public function listSchedules(): array
    {
        try {
            $json = $this->runSudoScriptCapture('announce-schedule.sh', ['list']);
        } catch (Exception $e) {
            // Listing schedules should not break the announcements UI when sudo/scripts
            // are missing on a partial upgrade (common on tarball-only deploys).
            $this->logger->warning('Could not list announcement schedules', [
                'error' => $e->getMessage(),
            ]);

            return [];
        }

        $decoded = json_decode($json, true);
        if (!is_array($decoded)) {
            $this->logger->warning('Announcement schedule list returned invalid JSON', [
                'output' => $json,
            ]);

            return [];
        }

        return $decoded;
    }"""

if old not in text:
    print("ERROR: AnnouncementsService.php does not match expected 4.3.x listSchedules() block.", file=sys.stderr)
    print("       Edit manually or upgrade to supermon-ng >= 4.3.0 first.", file=sys.stderr)
    sys.exit(1)

path.write_text(text.replace(old, new, 1))
print("  OK")
PY
}

patch_schedule_sh() {
  if [[ ! -f "$SCHEDULE_SH" ]]; then
    echo "ERROR: missing $SCHEDULE_SH" >&2
    echo "       Copy user_files/sbin/announce-*.sh from supermon-ng 4.3.0+ release." >&2
    return 1
  fi

  if grep -q 'PYTHON="${PYTHON:-/usr/bin/python3}"' "$SCHEDULE_SH"; then
    echo "[shell] announce-schedule.sh python path — already patched"
  else
    echo "[shell] Patching announce-schedule.sh for /usr/bin/python3 under sudo"
    backup "$SCHEDULE_SH"
    sed -i '/^CRON_TAG="announce-play.sh"$/a PYTHON="${PYTHON:-/usr/bin/python3}"' "$SCHEDULE_SH"
    sed -i 's/$(python3 -c/$("$PYTHON" -c/g' "$SCHEDULE_SH"
    echo "  OK"
  fi

  chmod 755 "$SCHEDULE_SH"
  for s in announce-play.sh announce-install.sh announce-tts.sh announce-delete.sh announce-voice-install.sh; do
    if [[ -f "${SBIN_DIR}/${s}" ]]; then
      chmod 755 "${SBIN_DIR}/${s}"
    fi
  done
  echo "[shell] announce-*.sh permissions set to 755 where present"
}

find_sudoers_file() {
  local f
  for f in /etc/sudoers.d/011-supermon-ng /etc/sudoers.d/011_www-nopasswd; do
    if [[ -f "$f" ]]; then
      echo "$f"
      return 0
    fi
  done
  return 1
}

patch_sudoers() {
  local sudoers
  if ! sudoers="$(find_sudoers_file)"; then
    echo "[sudoers] No 011-supermon-ng or 011_www-nopasswd found — add manually:"
    echo "  www-data ALL=(root) NOPASSWD: ${SCHEDULE_SH}"
    return 0
  fi

  if grep -qF "announce-schedule.sh" "$sudoers"; then
    echo "[sudoers] announce-schedule.sh already allowed in $sudoers"
    return 0
  fi

  echo "[sudoers] Adding announce-*.sh rules to $sudoers"
  backup "$sudoers"

  cat >>"$sudoers" <<EOF

# supermon-ng announcements (hotfix ${STAMP})
www-data ALL=(root) NOPASSWD: ${SBIN_DIR}/announce-play.sh
www-data ALL=(root) NOPASSWD: ${SBIN_DIR}/announce-install.sh
www-data ALL=(root) NOPASSWD: ${SBIN_DIR}/announce-tts.sh
www-data ALL=(root) NOPASSWD: ${SBIN_DIR}/announce-delete.sh
www-data ALL=(root) NOPASSWD: ${SBIN_DIR}/announce-schedule.sh
www-data ALL=(root) NOPASSWD: ${SBIN_DIR}/announce-voice-install.sh
EOF

  if ! visudo -cf "$sudoers" >/dev/null 2>&1; then
    echo "ERROR: sudoers validation failed — restoring backup" >&2
    mv -f "${sudoers}.bak.${STAMP}" "$sudoers"
    return 1
  fi
  echo "  OK"
}

verify() {
  echo
  echo "=== Verification ==="
  local missing=0
  for s in announce-play.sh announce-install.sh announce-tts.sh announce-delete.sh announce-schedule.sh announce-voice-install.sh; do
    if [[ ! -x "${SBIN_DIR}/${s}" ]]; then
      echo "  MISSING or not executable: ${SBIN_DIR}/${s}"
      missing=1
    fi
  done

  if [[ $missing -eq 1 ]]; then
    echo
    echo "Install missing scripts from a 4.3.0+ tarball or .deb, then re-run this hotfix."
    return 1
  fi

  echo -n "  sudo schedule list: "
  if out="$(sudo -u www-data sudo -n "$SCHEDULE_SH" list 2>&1)"; then
    echo "$out"
  else
    echo "FAILED"
    echo "  $out" >&2
    return 1
  fi

  echo
  echo "Done. Reload the dashboard and open Announcements — Playback/Create should work."
  echo "Scheduled tab shows entries only when cron list succeeds (see above)."
  echo "Logs: ${SUPERMON_DIR}/logs/app-$(date +%Y-%m-%d).log"
}

patch_php
patch_schedule_sh
patch_sudoers
verify
