#!/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) ensureAudioNodes lifecycle
s/function ensureAudioNodes\(\)\{\n/function ensureAudioNodes(){\n  console.log("[CP][audio] ensureAudioNodes()", { hasAudioCtx: !!audioCtx, hasMasterGain: !!masterGain });\n/s;

s/masterGain\.connect\(audioCtx\.destination\);/masterGain.connect(audioCtx.destination);\n  console.log("[CP][audio] masterGain connected to destination");/s;

# 2) guest track subscribe/unsubscribe
s/room\.on\(RoomEvent\.TrackSubscribed, \(track, pub, participant\)=>\{\n/room.on(RoomEvent.TrackSubscribed, (track, pub, participant)=>{\n    console.log("[CP][TrackSubscribed]", {\n      uid: participant?.identity || "",\n      name: participant?.name || "",\n      kind: track?.kind || "",\n      source: pub?.source || "",\n      trackName: pub?.trackName || track?.name || ""\n    });\n/s;

s/room\.on\(RoomEvent\.TrackUnsubscribed, \(track, pub, participant\)=>\{\n/room.on(RoomEvent.TrackUnsubscribed, (track, pub, participant)=>{\n    console.log("[CP][TrackUnsubscribed]", {\n      uid: participant?.identity || "",\n      name: participant?.name || "",\n      kind: track?.kind || "",\n      source: pub?.source || "",\n      trackName: pub?.trackName || track?.name || ""\n    });\n/s;

# 3) connectTrackToChannel diagnostics
s/function connectTrackToChannel\(idx, track\)\{/function connectTrackToChannel(idx, track){\n  console.log("[CP][mixer] connectTrackToChannel()", { idx, kind: track?.kind || "", hasTrack: !!track, hasAudioCtx: !!audioCtx, hasMasterGain: !!masterGain, slotUid: slots[idx]?.uid || "", slotName: slots[idx]?.name || "" });/s;

s/console\.warn\("connectTrackToChannel failed", err\);/console.warn("[CP][mixer] connectTrackToChannel failed", err);/s;

# 4) guest monitor toggle diagnostics
s/function toggleMicMonitor\(idx\)\{/function toggleMicMonitor(idx){\n  console.log("[CP][mixer] toggleMicMonitor()", { idx, before: slots[idx]?.micMonitorOn, uid: slots[idx]?.uid || "", name: slots[idx]?.name || "" });/s;

# 5) media routing diagnostics: video/audio elements
s/const hear = !isPreview;/const hear = !isPreview;\n      console.log("[CP][media-video] route", { isPreview, hear, programLocked: !!programLocked, srcType: src?.type || "", srcId: src?.id || "", itemKind: item?.kind || "", itemName: item?.name || "" });/g;

s/const hear = !isPreview;/const hear = !isPreview;\n      console.log("[CP][media-audio] route", { isPreview, hear, programLocked: !!programLocked, srcType: src?.type || "", srcId: src?.id || "", itemKind: item?.kind || "", itemName: item?.name || "" });/g;

s/attachMediaAudio\(v, item\);/console.log("[CP][media-video] attachMediaAudio", { id: item?.id || "", name: item?.name || "", kind: item?.kind || "", isPreview });\n        attachMediaAudio(v, item);/g;

s/attachMediaAudio\(a, item\);/console.log("[CP][media-audio] attachMediaAudio", { id: item?.id || "", name: item?.name || "", kind: item?.kind || "", isPreview });\n        attachMediaAudio(a, item);/g;

# 6) studio return source builder diagnostics
s/function getCurrentProgramVideoSource\(\)\{/function getCurrentProgramVideoSource(){\n  console.log("[CP][return] getCurrentProgramVideoSource()", { programLocked: !!programLocked, hasProgramSnapshot: !!programSnapshot, onAirBadge: (onAirBadge && onAirBadge.textContent) ? String(onAirBadge.textContent).trim() : "" });/s;

s/return \{ key: "", track: null, el: null \};/console.log("[CP][return] no capturable program source");\n  return { key: "", track: null, el: null };/s;

# 7) studio return audio/video publish diagnostics
s/async function ensureStudioReturnAudio\(\)\{/async function ensureStudioReturnAudio(){\n  console.log("[CP][return-audio] ensureStudioReturnAudio()", { hasRoom: !!room, hasLocalParticipant: !!(room && room.localParticipant), hasAudioCtx: !!audioCtx, hasMasterGain: !!masterGain, hasDest: !!studioReturnDest });/s;

s/console\.info\("\[StudioReturn\] published audio"\);/console.info("[StudioReturn] published audio");\n      console.log("[CP][return-audio] published", { trackName: "studio_return_audio", audioTracks: studioReturnDest?.stream?.getAudioTracks?.().length || 0 });/s;

s/console\.warn\("\[StudioReturn\] audio publish failed", e\);/console.warn("[StudioReturn] audio publish failed", e);\n    console.warn("[CP][return-audio] failed", e);/s;

s/async function refreshStudioReturnVideo\(\)\{/async function refreshStudioReturnVideo(){\n  console.log("[CP][return-video] refreshStudioReturnVideo()", { hasRoom: !!room, hasLocalParticipant: !!(room && room.localParticipant), existingSourceKey: studioReturnVideoSourceKey || "" });/s;

s/const src = getCurrentProgramVideoSource\(\);/const src = getCurrentProgramVideoSource();\n    console.log("[CP][return-video] source", { key: src?.key || "", hasTrack: !!(src && src.track), tag: src?.el?.tagName || "" });/s;

s/console\.info\("\[StudioReturn\] published video", srcKey\);/console.info("[StudioReturn] published video", srcKey);\n    console.log("[CP][return-video] published", { trackName: "studio_return_video", srcKey, tag: src?.el?.tagName || "" });/s;

s/console\.warn\("\[StudioReturn\] video publish failed", e\);/console.warn("[StudioReturn] video publish failed", e);\n    console.warn("[CP][return-video] failed", e);/s;

# 8) republish scheduler diagnostics
s/function scheduleStudioReturnRepublish\(delay\)\{/function scheduleStudioReturnRepublish(delay){\n  console.log("[CP][return] scheduleStudioReturnRepublish()", { delay });/s;

# 9) active on-air update diagnostics
s/function updateOnAirPanel\(\)\{\n  try\{ Promise\.resolve\(\)\.then\(\(\)=>ensureStudioReturnPublish\(\)\)\.catch\(\(\)=>\{\}\); \}catch\(_\)\{ \}/function updateOnAirPanel(){\n  console.log("[CP][onair] updateOnAirPanel()", { programLocked: !!programLocked, onAirBadge: (onAirBadge && onAirBadge.textContent) ? String(onAirBadge.textContent).trim() : "", previewType: previewSource?.type || "" });\n  try{ Promise.resolve().then(()=>ensureStudioReturnPublish()).catch(()=>{}); }catch(_){ }/s;
' "$JS"

echo
echo "Patch complete."
echo
echo "Verify markers:"
grep -n '\[CP\]\[audio\]\|\[CP\]\[mixer\]\|\[CP\]\[media-video\]\|\[CP\]\[media-audio\]\|\[CP\]\[return\]\|\[CP\]\[return-audio\]\|\[CP\]\[return-video\]\|\[CP\]\[onair\]' "$JS" | head -80
