let mediaErrorCount = 0;
let syncCheckTimer = null;
let baseTime = null;
let baseWall = performance.now();

function getCacheBusterUrl(urlRaw) {
//  return urlRaw + '?t=' + new Date().getTime(); // cache buster added
  return urlRaw;
}

function setCheckTimer(hls, video) {
  if (syncCheckTimer) {
    clearInterval(syncCheckTimer);
    syncCheckTimer = null;
  }
  baseTime = video.currentTime;
  syncCheckTimer = setInterval(() => {
    const audioPTS = hls.audioTrackController?.audioTrack?.details?.fragments?.[0]?.startPTS;
    const videoPTS = hls.streamController?.videoTrack?.details?.fragments?.[0]?.startPTS;
    if (audioPTS !== undefined && videoPTS !== undefined) {
      const diff = (audioPTS - videoPTS) * 1000;
      if (Math.abs(diff) > 200) {
        console.warn('av differencies: ${diff.toFixed(1)}ms');
      }
    }
    const expected = baseTime + (performance.now() - baseWall) / 1000;
    const drift = video.currentTime - expected;

    if (Math.abs(drift) > 0.7) {
      video.currentTime -= drift * 0.5; // half back now
    
      baseTime = video.currentTime;
      baseWall = performance.now();
    }
  }, 1000);
}

function startHls(hls, strURLSave, strVideo, retryCount = 0) {
  const video = document.getElementById(strVideo);
  const urlRaw = document.getElementById(strURLSave).value;

  // erase the old source and reset its buffer
  video.pause();
  video.removeAttribute('src');
  video.load();

  // set check timer
  setCheckTimer(hls, video);

  hls.attachMedia(video);
  hls.loadSource(getCacheBusterUrl(urlRaw));

  if (!hls._errorHandlerAdded) {
    let mediaErrorCount = 0;
    hls.on(Hls.Events.ERROR, function (event, data) {
      console.error(`[HLS ERROR] Type: ${data.type}, Details: ${data.details}, Fatal: ${data.fatal}`);

      if (data.fatal) {
        switch (data.type) {
          case Hls.ErrorTypes.NETWORK_ERROR:
            console.log("Fatal network error encountered, trying to recover...");
            setTimeout(() => {
              if (data.details && data.details.startsWith("MANIFEST_")) {
                hls.loadSource(getCacheBusterUrl(urlRaw));
              } else {
                hls.startLoad();
              }
            }, 1000);
            break;

          case Hls.ErrorTypes.MEDIA_ERROR:
            if (mediaErrorCount < 1) {
              console.log("Fatal media error encountered, trying to recover...");
              hls.recoverMediaError();
              mediaErrorCount++;
            } else {
              console.log("Too many media errors, restarting HLS...");
              hls.destroy();
              video.removeAttribute('src');
              video.load();
              const hlsNew = new Hls({
                maxAudioFramesDrift: 1,
                maxBufferHole: 0.1
              });
              startHls(hlsNew, strURLSave, strVideo, retryCount + 1);
            }
            break;

          default:
            console.log("Unrecoverable error. Destroying HLS.");
            hls.destroy();
            video.removeAttribute('src');
            video.load();
            break;
        }
      }
    });
    hls._errorHandlerAdded = true;
  }
}
