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

JOINPHP="${1:-/home/itahukamedia/public_html/studio.itahukamedia.com/public/join.php}"
TS="$(date +%Y%m%d_%H%M%S)"

if [ ! -f "$JOINPHP" ]; then
  echo "File not found: $JOINPHP"
  exit 1
fi

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

TMP_HELPERS="$(mktemp)"
TMP_OUT="$(mktemp)"

need_any=0

if ! grep -q 'function createVUMeter(' "$JOINPHP"; then
  need_any=1
  cat >> "$TMP_HELPERS" <<'EOF'
  function createVUMeter(barEl, dbEl){
    const SEGMENTS = 20;
    if (!barEl) {
      return {
        analyser: null,
        source: null,
        data: new Float32Array(2048),
        setLevelFromDb: function(){},
        setIdle: function(){},
        attachTrack: function(){},
        detach: function(){},
        tick: function(){}
      };
    }

    barEl.innerHTML = "";
    const segs = [];
    for (let i = 0; i < SEGMENTS; i++){
      const d = document.createElement("div");
      d.className = "seg";
      if (i >= SEGMENTS - 3) d.classList.add("hot");
      else if (i >= SEGMENTS - 7) d.classList.add("warn");
      barEl.appendChild(d);
      segs.push(d);
    }

    return {
      analyser: null,
      source: null,
      data: new Float32Array(2048),

      setLevelFromDb: function(db){
        const clamped = Math.max(-60, Math.min(0, db));
        const norm = (clamped + 60) / 60;
        const onCount = Math.round(norm * SEGMENTS);
        for (let i = 0; i < SEGMENTS; i++){
          segs[i].classList.toggle("on", i < onCount);
        }
        if (dbEl) dbEl.textContent = `${clamped.toFixed(1)} dB`;
      },

      setIdle: function(){
        for (const s of segs) s.classList.remove("on");
        if (dbEl) dbEl.textContent = "— dB";
      },

      attachTrack: function(track){
        this.detach();
        const mst = getMediaStreamTrack(track);
        if (!mst) {
          this.setIdle();
          return;
        }
        const ctx = ensureAudioContext();
        const stream = new MediaStream([mst]);
        const source = ctx.createMediaStreamSource(stream);
        const analyser = ctx.createAnalyser();
        analyser.fftSize = 2048;
        analyser.smoothingTimeConstant = 0.85;
        source.connect(analyser);
        this.source = source;
        this.analyser = analyser;
      },

      detach: function(){
        try { if (this.source) this.source.disconnect(); } catch(_){}
        this.source = null;
        this.analyser = null;
        this.setIdle();
      },

      tick: function(){
        if (!this.analyser) return;
        this.analyser.getFloatTimeDomainData(this.data);
        let sum = 0;
        for (let i = 0; i < this.data.length; i++){
          const x = this.data[i];
          sum += x * x;
        }
        const rms = Math.sqrt(sum / this.data.length);
        const db = (rms > 0) ? (20 * Math.log10(rms)) : -60;
        this.setLevelFromDb(db);
      }
    };
  }

EOF
fi

if ! grep -q 'async function fetchToken(' "$JOINPHP"; then
  need_any=1
  cat >> "$TMP_HELPERS" <<'EOF'
  async function fetchToken({roomName, name, publish, subscribe}){
    const base = (els.tokenep && els.tokenep.value.trim()) || DEFAULT_TOKEN_EP;
    const u = new URL(base, location.href);
    u.searchParams.set("room", roomName);
    u.searchParams.set("name", name);
    u.searchParams.set("publish", publish ? "1" : "0");
    u.searchParams.set("subscribe", subscribe ? "1" : "0");

    const res = await fetch(u.toString(), { credentials: "same-origin" });
    if (!res.ok){
      const txt = await res.text().catch(() => "");
      throw new Error(`Token endpoint failed: ${res.status} ${res.statusText} ${txt}`.trim());
    }
    const data = await res.json();
    if (!data || !data.token) throw new Error("Token endpoint did not return {token}");
    return data.token;
  }

EOF
fi

if ! grep -q 'function cleanupTracks(' "$JOINPHP"; then
  need_any=1
  cat >> "$TMP_HELPERS" <<'EOF'
  function cleanupTracks(){
    try { detachLocal(); } catch(_){}
    try { if (localVU) localVU.detach(); } catch(_){}
    try { if (localAudio) localAudio.stop(); } catch(_){}
    try { if (localVideo) localVideo.stop(); } catch(_){}
    localAudio = null;
    localVideo = null;
  }

EOF
fi

if [ "$need_any" -eq 0 ]; then
  echo "No missing helper functions detected. Nothing changed."
  rm -f "$TMP_HELPERS" "$TMP_OUT"
  exit 0
fi

awk -v helpers="$TMP_HELPERS" '
BEGIN{
  inserted = 0
  while ((getline line < helpers) > 0) block = block line "\n"
  close(helpers)
}
{
  if (!inserted && $0 ~ /^  function boot\(\)\{/){
    printf "%s", block
    inserted = 1
  }
  print
}
END{
  if (!inserted) {
    printf "%s", block
  }
}
' "$JOINPHP" > "$TMP_OUT"

mv "$TMP_OUT" "$JOINPHP"
rm -f "$TMP_HELPERS"

echo
echo "Patch complete."
echo
echo "Run:"
echo "php -l \"$JOINPHP\""
echo "grep -n \"function createVUMeter\\|async function fetchToken\\|function cleanupTracks\\|function boot\" \"$JOINPHP\""
