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

ROOT="${1:-/home/itahukamedia/public_html/studio.itahukamedia.com/public}"
JS="$ROOT/assets/js/modules/coproducer.inline-main.js"
TS="$(date +%Y%m%d_%H%M%S)"

cp -a "$JS" "$JS.bak.$TS"
echo "Backup created: $JS.bak.$TS"

perl -0pi -e '
# ------------------------------------------------------------------
# 1) Add one-time user gesture unlock for AudioContext
# ------------------------------------------------------------------
s/const btnTake = document\.getElementById\("btnTake"\);/const btnTake = document.getElementById("btnTake");\n\nlet __cpAudioUnlocked = false;\nfunction unlockCoproducerAudioOnce(){\n  if (__cpAudioUnlocked) return;\n  __cpAudioUnlocked = true;\n  try{ resumeAudioContext(); }catch(_){}\n  try{ ensureAudioNodes(); }catch(_){}\n  try{\n    if (audioCtx && audioCtx.state === "suspended"){\n      audioCtx.resume().catch(()=>{});\n    }\n  }catch(_){}\n}\n\nwindow.addEventListener("pointerdown", unlockCoproducerAudioOnce, { passive:true });\nwindow.addEventListener("keydown", unlockCoproducerAudioOnce, { passive:true });\nwindow.addEventListener("touchstart", unlockCoproducerAudioOnce, { passive:true });/s;

# ------------------------------------------------------------------
# 2) Add studio-return publish guards/lock
# ------------------------------------------------------------------
s/let studioReturnVideoSourceKey = "";/let studioReturnVideoSourceKey = "";\nlet __studioReturnPublishInFlight = false;\nlet __studioReturnAudioPublishInFlight = false;\nlet __studioReturnVideoPublishInFlight = false;/s;

# ------------------------------------------------------------------
# 3) Add helper to verify room is actually usable
# ------------------------------------------------------------------
s/function supportsCaptureStream\(videoEl\)\{/function canPublishStudioReturn(){\n  try{\n    if (!room) return false;\n    if (!room.localParticipant) return false;\n    return room.state === "connected" || room.state === "reconnecting" || room.state === 1;\n  }catch(_){ }\n  return false;\n}\n\nfunction supportsCaptureStream(videoEl){/s;

# ------------------------------------------------------------------
# 4) Harden ensureStudioReturnAudio()
# ------------------------------------------------------------------
s/async function ensureStudioReturnAudio\(\)\{\n  try\{\n    if \(!room \|\| !room\.localParticipant\) return;/async function ensureStudioReturnAudio(){\n  try{\n    if (!canPublishStudioReturn()) return;\n    if (__studioReturnAudioPublishInFlight) return;/s;

s/const pubs = Array\.from\(room\.localParticipant\?\.audioTrackPublications\?\.values\?\.\(\) \|\| \[\]\);/const pubs = Array.from(room.localParticipant?.audioTrackPublications?.values?.() || []);\n    const alreadyPublishing = __studioReturnAudioPublishInFlight;/s;

s/if \(!studioReturnAudio \|\| !existingPub\)\{/if (!studioReturnAudio || !existingPub){\n      __studioReturnAudioPublishInFlight = true;/s;

s/console\.info\("\[StudioReturn\] published audio"\);/console.info("[StudioReturn] published audio");\n      __studioReturnAudioPublishInFlight = false;/s;

s/console\.warn\("\[StudioReturn\] audio publish failed", e\);/console.warn("[StudioReturn] audio publish failed", e);\n    __studioReturnAudioPublishInFlight = false;/s;

# ------------------------------------------------------------------
# 5) Harden refreshStudioReturnVideo()
# ------------------------------------------------------------------
s/async function refreshStudioReturnVideo\(\)\{\n  try\{\n    if \(!room \|\| !room\.localParticipant\) return;/async function refreshStudioReturnVideo(){\n  try{\n    if (!canPublishStudioReturn()) return;\n    if (__studioReturnVideoPublishInFlight) return;/s;

s/if \(studioReturnVideo && currentPub && studioReturnVideoSourceKey === srcKey\) return;/if (studioReturnVideo && currentPub && studioReturnVideoSourceKey === srcKey) return;\n\n    __studioReturnVideoPublishInFlight = true;/s;

s/console\.info\("\[StudioReturn\] published video", srcKey\);/console.info("[StudioReturn] published video", srcKey);\n    __studioReturnVideoPublishInFlight = false;/s;

s/console\.warn\("\[StudioReturn\] video publish failed", e\);/console.warn("[StudioReturn] video publish failed", e);\n    __studioReturnVideoPublishInFlight = false;/s;

# ------------------------------------------------------------------
# 6) Serialize ensureStudioReturnPublish()
# ------------------------------------------------------------------
s/async function ensureStudioReturnPublish\(\)\{\n  await ensureStudioReturnAudio\(\);\n  await refreshStudioReturnVideo\(\);\n\}/async function ensureStudioReturnPublish(){\n  if (!canPublishStudioReturn()) return;\n  if (__studioReturnPublishInFlight) return;\n  __studioReturnPublishInFlight = true;\n  try{\n    await ensureStudioReturnAudio();\n    await refreshStudioReturnVideo();\n  }finally{\n    __studioReturnPublishInFlight = false;\n  }\n}/s;

# ------------------------------------------------------------------
# 7) updateOnAirPanel(): remove immediate republish spam
# ------------------------------------------------------------------
s/function updateOnAirPanel\(\)\{\n  try\{ Promise\.resolve\(\)\.then\(\(\)=>ensureStudioReturnPublish\(\)\)\.catch\(\(\)=>\{\}\); \}catch\(_\)\{ \}/function updateOnAirPanel(){/s;

# ------------------------------------------------------------------
# 8) TAKE hook: use delayed scheduled republish only
# ------------------------------------------------------------------
s/requestAnimationFrame\(\(\)=>\{\n\s*try\{ ensureStudioReturnPublish\(\); \}catch\(_\)\{\}\n\s*\}\);/requestAnimationFrame(()=>{\n      try{ scheduleStudioReturnRepublish(320); }catch(_){ }\n    });/s;

# ------------------------------------------------------------------
# 9) After successful join, unlock audio and schedule republish once
# ------------------------------------------------------------------
s/joined = true;\n      setStatus\("In room"\);\n      syncButtons\(\);/joined = true;\n      setStatus("In room");\n      unlockCoproducerAudioOnce();\n      syncButtons();/s;

s/updateOnAirPanel\(\);\n      updatePreviewPanel\(\);/updateOnAirPanel();\n      updatePreviewPanel();\n      try{ scheduleStudioReturnRepublish(220); }catch(_){ }/s;

# ------------------------------------------------------------------
# 10) Guest audio path: always resume audio context before channel connect
# ------------------------------------------------------------------
s/resumeAudioContext\(\);\n        ensureAudioNodes\(\);\n        connectTrackToChannel\(s\.idx, track\);/unlockCoproducerAudioOnce();\n        resumeAudioContext();\n        ensureAudioNodes();\n        connectTrackToChannel(s.idx, track);/s;
' "$JS"

echo
echo "Patch complete: $JS"
echo
echo "Verify:"
grep -n "unlockCoproducerAudioOnce\\|canPublishStudioReturn\\|__studioReturnPublishInFlight\\|scheduleStudioReturnRepublish(320)\\|scheduleStudioReturnRepublish(220)" "$JS"
