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

if [ "$#" -lt 1 ]; then
  echo "Usage: $0 /path/to/studio/public"
  echo "Example: $0 /home/itahukamedia/public_html/studio.itahukamedia.com/public"
  exit 1
fi

ROOT="$1"
JOIN="$ROOT/join.php"

if [ ! -f "$JOIN" ]; then
  echo "Missing file: $JOIN" >&2
  exit 1
fi

if ! command -v php >/dev/null 2>&1; then
  echo "ERROR: php CLI not found in PATH." >&2
  exit 1
fi

STAMP="$(date +%Y%m%d_%H%M%S)"
cp -a "$JOIN" "$JOIN.bak.$STAMP"
echo "Backup created: $JOIN.bak.$STAMP"

php <<'PHP' "$JOIN"
<?php
$joinPath = $argv[1];

function fail($msg){ fwrite(STDERR, $msg . PHP_EOL); exit(1); }
function read_strict($p){ $c = file_get_contents($p); if ($c === false) fail("Cannot read: $p"); return $c; }
function write_strict($p, $c){ if (file_put_contents($p, $c) === false) fail("Cannot write: $p"); }
function patch_once(&$text, $search, $replace, $label){
  if (strpos($text, $replace) !== false) {
    echo "Already patched: $label\n";
    return;
  }
  $count = substr_count($text, $search);
  if ($count !== 1) fail("Patch failed for $label: expected 1 exact match, got $count");
  $text = str_replace($search, $replace, $text);
  echo "Patched: $label\n";
}

$join = read_strict($joinPath);

/* 1) Add cam+mic permission prompt helper before connect */
patch_once(
  $join,
  <<<'TXT'
  async function fetchToken({roomName, name, publish, subscribe}){
TXT,
  <<<'TXT'
  async function promptJoinDevices(){
    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) return;
    const stream = await navigator.mediaDevices.getUserMedia({ audio:true, video:true });
    try{
      for (const t of (stream.getTracks() || [])){
        try{ t.stop(); }catch(_){}
      }
    }catch(_){}
  }

  async function fetchToken({roomName, name, publish, subscribe}){
TXT,
  'add join AV prompt helper'
);

/* 2) Force remote stage to use studio-return only */
patch_once(
  $join,
  <<<'TXT'
  function pickRemoteVideoParticipant(){
    if (!lkRoom) return null;
    const remotes = Array.from(lkRoom.remoteParticipants.values());
    for (const p of remotes){
      for (const pub of p.videoTrackPublications.values()){
        if (pub.track) return p;
      }
    }
    for (const p of remotes){
      if (p.videoTrackPublications.size > 0) return p;
    }
    return remotes[0] || null;
  }

  function firstSubscribedTrack(publications){
    for (const pub of publications.values()){
      if (pub.track) return pub.track;
    }
    return null;
  }

  function attachRemoteFromParticipant(p){
    if (!p){
      clearRemote();
      if (remoteVU) remoteVU.detach();
      return;
    }

    const v = firstSubscribedTrack(p.videoTrackPublications);
    detachRemoteVideo();

    if (!v){
      if (els.remoteEmpty) els.remoteEmpty.style.display = "flex";
      if (els.tagRemote) els.tagRemote.textContent = `Remote: ${p.identity || p.name || "participant"}`;
    } else {
      remoteVideoTrack = v;
      try { v.attach(els.remoteVideo); } catch(_){}
      if (els.remoteEmpty) els.remoteEmpty.style.display = "none";
      if (els.tagRemote) els.tagRemote.textContent = `Remote: ${p.identity || p.name || "participant"}`;
    }

    const a = firstSubscribedTrack(p.audioTrackPublications);
    if (remoteVU){
      if (a) remoteVU.attachTrack(a);
      else remoteVU.detach();
    }
  }
TXT,
  <<<'TXT'
  function pickRemoteVideoParticipant(){
    if (!lkRoom) return null;
    const remotes = Array.from(lkRoom.remoteParticipants.values());
    return remotes.find(p => String((p && p.identity) || "").trim() === "studio-return") || null;
  }

  function firstSubscribedTrack(publications){
    for (const pub of publications.values()){
      if (pub.track) return pub.track;
    }
    return null;
  }

  function pickNamedTrack(publications, wantedTrackName){
    if (!publications) return null;
    for (const pub of publications.values()){
      if (String((pub && pub.trackName) || "") === wantedTrackName && pub.track) return pub.track;
    }
    return null;
  }

  function attachRemoteFromParticipant(p){
    if (!p){
      clearRemote();
      if (remoteVU) remoteVU.detach();
      if (els.tagRemote) els.tagRemote.textContent = "Remote: studio-return";
      return;
    }

    const v = pickNamedTrack(p.videoTrackPublications, "studio_return_video") || firstSubscribedTrack(p.videoTrackPublications);
    detachRemoteVideo();

    if (!v){
      if (els.remoteEmpty) els.remoteEmpty.style.display = "flex";
      if (els.tagRemote) els.tagRemote.textContent = "Remote: studio-return";
    } else {
      remoteVideoTrack = v;
      try { v.attach(els.remoteVideo); } catch(_){}
      if (els.remoteEmpty) els.remoteEmpty.style.display = "none";
      if (els.tagRemote) els.tagRemote.textContent = "Remote: studio-return";
    }

    const a = pickNamedTrack(p.audioTrackPublications, "studio_return_audio") || firstSubscribedTrack(p.audioTrackPublications);
    if (remoteVU){
      if (a) remoteVU.attachTrack(a);
      else remoteVU.detach();
    }
  }
TXT,
  'force remote stage to studio-return AV'
);

/* 3) Remove studio-return from guest strip */
patch_once(
  $join,
  <<<'TXT'
    const participants = [];
    if (lkRoom.localParticipant) participants.push({ key:"local", p: lkRoom.localParticipant, isLocal:true });
    for (const p of lkRoom.remoteParticipants.values()){
      participants.push({ key: p.sid || p.identity || String(Math.random()), p, isLocal:false });
    }
TXT,
  <<<'TXT'
    const participants = [];
    if (lkRoom.localParticipant) participants.push({ key:"local", p: lkRoom.localParticipant, isLocal:true });
    for (const p of lkRoom.remoteParticipants.values()){
      if (String((p && p.identity) || "").trim() === "studio-return") continue;
      participants.push({ key: p.sid || p.identity || String(Math.random()), p, isLocal:false });
    }
TXT,
  'exclude studio-return from guest strip'
);

/* 4) Prompt for AV before fetch token/connect */
patch_once(
  $join,
  <<<'TXT'
      const lkUrl = (els.lkurl && els.lkurl.value.trim()) || DEFAULT_LK_URL;
      const token = await fetchToken({ roomName, name, publish: true, subscribe: true });

      await lkRoom.connect(lkUrl, token);
TXT,
  <<<'TXT'
      const lkUrl = (els.lkurl && els.lkurl.value.trim()) || DEFAULT_LK_URL;
      await promptJoinDevices();
      const token = await fetchToken({ roomName, name, publish: true, subscribe: true });

      await lkRoom.connect(lkUrl, token);
TXT,
  'prompt AV before connect'
);

/* 5) Auto-publish BOTH mic and cam after connect */
patch_once(
  $join,
  <<<'TXT'
      buildShare();
      refreshGuestStrip();

      // local screen stays "Not publishing" until MIC/CAM pressed
      detachLocal();
      if (localVU) localVU.setIdle();

      await enumerateDevices().catch(()=>{});
TXT,
  <<<'TXT'
      buildShare();
      refreshGuestStrip();

      // Publish BOTH camera and microphone immediately after connect.
      await ensureLocalCam();
      await ensureLocalMic();
      attachLocal();
      if (localVU && localAudio) localVU.attachTrack(localAudio);

      await enumerateDevices().catch(()=>{});
TXT,
  'auto-publish full AV after connect'
);

/* 6) Share URL should not fallback to camA room text */
patch_once(
  $join,
  <<<'TXT'
    base.searchParams.set("room", ((els.room && els.room.value.trim()) || "camA"));
TXT,
  <<<'TXT'
    base.searchParams.set("room", ((els.room && els.room.value.trim()) || <?php echo json_encode($roomName); ?>));
TXT,
  'share URL uses actual room fallback'
);

/* 7) Boot room should use actual project room, not camA */
patch_once(
  $join,
  <<<'TXT'
    if (els.room) els.room.value = qsGet("room", "camA");
TXT,
  <<<'TXT'
    if (els.room) els.room.value = qsGet("room", <?php echo json_encode($roomName); ?>);
TXT,
  'boot room uses actual project room'
);

write_strict($joinPath, $join);
echo "Done: $joinPath\n";
PHP

echo
echo "Patch complete."
echo
echo "Run:"
echo "php -l \"$JOIN\""
echo
echo "Then hard-refresh ONLY join.php and test:"
echo "https://studio.itahukamedia.com/join.php?project=proj_0027932e57a24f63"