
console.log('SSTTS with four buttons loaded 28');


const today = new Date().toISOString().slice(0, 10); // format: "YYYY-MM-DD"
const lastDate = localStorage.getItem('sstts_last_date');

if (lastDate !== today) {
  localStorage.setItem('sstts_last_date', today);
  localStorage.setItem('sstts_plays', '0');
  localStorage.setItem('sstts_restarts', '0');
}

let playCount    = parseInt(localStorage.getItem('sstts_plays')    || '0', 10);
let restartCount = parseInt(localStorage.getItem('sstts_restarts') || '0', 10);
let limitAlertShown = false;


let isSpeakingInProgress = false;
let hasEnded = false;
let lastCharIndex = 0;
let totalChars = 0;


(function(){

  const BAR_ID = 'sstts-bar';
  let lastRange   = null;           // stores original highlight range
  let selectedText = '';
  let utterance    = null;
  let dragOffset   = { x: 0, y: 0 };



let voicesReady = false;

const loadVoices = new Promise((resolve) => {
  const check = () => {
    const voices = speechSynthesis.getVoices();
    if (voices.length > 0) {
      voicesReady = true;
console.log("Available voices:", speechSynthesis.getVoices());

      resolve();
    }
  };
  check(); // Check immediately
  let attempts = 0;
  const interval = setInterval(() => {
    attempts++;
    check();
    if (voicesReady || attempts > 20) { // ~2 seconds max wait
      clearInterval(interval);
  if (!voicesReady) {
    console.warn("SpeechSynthesis voices failed to load within expected time.");
  }
      resolve();
    }
  }, 100);
});



function checkAudioSupport() {
  if (!('speechSynthesis' in window)) {
    alert("Your browser does not support speech synthesis.");
    return false;
  }
  if (!voicesReady) {
    alert("Speech synthesis voices are not ready yet. Please wait a moment and try again.");
    return false;
  }
  return true;
}



  /*--------------------------------------------------------------
   *  analytics helper  →  POST /wp-json/sstts/v1/hit
   *-------------------------------------------------------------*/


function pingMetric(type){


  fetch('/wp-json/sstts/v1/hit', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ type })
  }).then(res => {
    if (res.ok) {
      if (type === 'play') {
        playCount++;
        localStorage.setItem('sstts_plays', playCount);
      }
      if (type === 'restart') {
        restartCount++;
        localStorage.setItem('sstts_restarts', restartCount);
      }


    }
}).catch((err) => {
  console.error('Speech analytics logging failed:', err);
});
}


  /*--------------------------------------------------------------
   *  utility: was click inside old range?
   *-------------------------------------------------------------*/
  function isClickInsideLastRange(event){
    if(!lastRange) return false;
    const range = document.caretRangeFromPoint
      ? document.caretRangeFromPoint(event.clientX,event.clientY)
      : document.caretPositionFromPoint
        ? (()=>{ const p=document.caretPositionFromPoint(event.clientX,event.clientY);
                 const r=document.createRange();
                 r.setStart(p.offsetNode,p.offset);
                 r.setEnd  (p.offsetNode,p.offset);
                 return r; })()
        : null;
    if(!range) return false;
    return lastRange.compareBoundaryPoints(Range.START_TO_START, range) <= 0 &&
           lastRange.compareBoundaryPoints(Range.END_TO_END,   range) >= 0;
  }

  /*--------------------------------------------------------------*/
  document.addEventListener('mouseup', e => {
    const bar = document.getElementById(BAR_ID);
    const clickedInsideBar = e.target.closest(`#${BAR_ID}`);

    const text = window.getSelection().toString().trim();

    if (clickedInsideBar) return; // Do nothing if clicked inside the panel

    if (text.length) {
      if (speechSynthesis.speaking || speechSynthesis.paused) speechSynthesis.cancel();
      selectedText = text;
      showBar(e.pageX, e.pageY);
    } else {
      if (speechSynthesis.speaking && isClickInsideLastRange(e)) {
        e.preventDefault();
        return;
      }

      hideBar(); // Hide panel only if not selecting new text or speaking inside old range
    }
  });


  /*--------------------------------------------------------------*/
  function showBar(x,y){
    window.speechSynthesis.cancel();
    hideBar();
    const bar=document.createElement('div');
    bar.id=BAR_ID;
    bar.className='sstts-bar';
    Object.assign(bar.style,{left:`${x}px`,top:`${y+15}px`});
    let pro = typeof sstts_data !== 'undefined' && sstts_data.is_paying_user;


     

    if (!sstts_data?.is_paying_user) {
      bar.innerHTML = `
        <div class="sstts-header" style="cursor:move;user-select:none;margin-right:10px;">⇕</div>
        <button data-act="play" title="Play">▶</button>`;
    }


    bar.addEventListener('mousedown', e=>e.stopPropagation());
    bar.addEventListener('click', handleClick);
    makeDraggable(bar);
    document.body.appendChild(bar);
    updateButtons('ready');
  }

  function makeDraggable(el){
    const header = el.querySelector('.sstts-header');
    if (!header) return;
    header.addEventListener('mousedown', function(e){
      e.preventDefault();
      dragOffset.x = e.clientX - el.offsetLeft;
      dragOffset.y = e.clientY - el.offsetTop;
      document.addEventListener('mousemove', onMouseMove);
      document.addEventListener('mouseup', onMouseUp);
    });
    function onMouseMove(e){
      el.style.left = `${e.clientX - dragOffset.x}px`;
      el.style.top  = `${e.clientY - dragOffset.y}px`;
    }
    function onMouseUp(){
      document.removeEventListener('mousemove', onMouseMove);
      document.removeEventListener('mouseup', onMouseUp);
    }
  }

  function hideBar(){
    window.speechSynthesis.cancel();
    isSpeakingInProgress = false; // reset flag
    utterance = null;

    const bar = document.getElementById(BAR_ID);
    if (bar) bar.remove();
    clearSpokenHighlight();
  }


  function ensureHighlight(){
    const selText=window.getSelection().toString().trim();
    if(!selText.length && lastRange){
      const sel=window.getSelection();
      sel.removeAllRanges();
      sel.addRange(lastRange.cloneRange());
    }
  }



  /*--------------------------------------------------------------*/
function handleClick(e) {
  const button = e.target.closest('button[data-act]');
  const act = button ? button.dataset.act : null;

  console.log(`Clicked element: ${act || 'none'}`);

  if (!act) return;

  // Only cancel for certain buttons, not for pause/resume
  if ((act === 'restart' || act === 'close') && (speechSynthesis.speaking || speechSynthesis.pending)) {
    console.log('Cancelling ongoing speech for restart/close.');
    window.speechSynthesis.cancel();
  }


  switch (act) {


    case 'play':
	  console.log('Play button clicked.');
 	 // Only resume if we truly have a paused, not-ended utterance
  	if (utterance && speechSynthesis.paused && !hasEnded) {
    		resumeSpeech();
  	} else {
    		startSpeech();
  	}
  	pingMetric('play');
  	break;





    default:
      console.warn('Unhandled action:', act);
  }
}


  /*--------------------------------------------------------------*/


function pauseSpeech(){
  if (speechSynthesis.speaking) {
    // If we’re basically done (e.g., last 5%), treat as ended to avoid resume() no-op
    const nearEnd = totalChars > 0 && (lastCharIndex / totalChars) >= 0.95;
    if (nearEnd) {
      console.log('Paused near end — treating as ended to avoid resume dead state.');
      hasEnded = true;
      // Cancel to clear engine queue and reset UI
      window.speechSynthesis.cancel();
      isSpeakingInProgress = false;
      updateButtons('ready');
      return;
    }
    console.log('Speech paused.');
    updateButtons('paused');
    isSpeakingInProgress = false;
    speechSynthesis.pause();
  }
}



  /*--------------------------------------------------------------*/


function resumeSpeech() {
  if (utterance && speechSynthesis.paused && !hasEnded) {
    console.log('Resuming speech.');
    speechSynthesis.resume();
    updateButtons('speaking');
    isSpeakingInProgress = true;
  } else {
    console.warn('Resume not possible (not paused or already ended). Starting fresh.');
    startSpeech();
  }
}





  /*--------------------------------------------------------------*/

function startSpeech() {
  // Always cancel any ongoing speech first
  window.speechSynthesis.cancel();
  isSpeakingInProgress = false;

  loadVoices.then(() => {
    setTimeout(() => {
      if (!checkAudioSupport()) return;

      ensureHighlight();
      if (!selectedText.length) {
        console.warn('No text selected.');
        return;
      }

      const voices = speechSynthesis.getVoices();
      if (!voices.length) {
        alert("Voices not yet loaded. Please try again in a moment.");
        return;
      }

      try {
        const sel = window.getSelection();
        if (sel && sel.rangeCount) {
          lastRange = sel.getRangeAt(0).cloneRange();
        }
      } catch (err) {
        console.warn('Error capturing selection range:', err);
        lastRange = null;
      }

      utterance = new SpeechSynthesisUtterance(selectedText);
hasEnded = false;
lastCharIndex = 0;
totalChars = selectedText.length;


      utterance.voice = voices.find(v => v.lang.startsWith('en')) || voices[0];

      console.log("Utterance initialized with voice:", utterance.voice?.name || 'None');

      isSpeakingInProgress = true;

utterance.onboundary = ev => {
  // Some engines don’t set name === 'word' reliably; keep your check if you prefer,
  // but we’ll still track charIndex defensively.
  if (!lastRange) return;
  lastCharIndex = ev.charIndex || lastCharIndex; // track progress
  const sel = window.getSelection();
  if (sel && sel.rangeCount) sel.removeAllRanges();
  highlightSpoken(ev.charIndex);
};

utterance.onend = () => {
  console.log("Speech ended.");
  hasEnded = true;
  isSpeakingInProgress = false;
  updateButtons('ready');
  clearSpokenHighlight();

  const curSel = window.getSelection().toString().trim();
  if (!curSel.length && lastRange) {
    const sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(lastRange.cloneRange());
  }
};

      utterance.onerror = (err) => {
        if (err.error === 'canceled') {
          console.log('Speech canceled by design.');
          return;
        }
        console.error('Speech synthesis error:', err);
        isSpeakingInProgress = false;
        updateButtons('ready');
      };

      speechSynthesis.speak(utterance);
      updateButtons('speaking');
    }, 200);
  });
}



  /*--------------------------------------------------------------*/
  function highlightSpoken(charIndex){
    clearSpokenHighlight();
    if(!lastRange) return;
    let range=lastRange.cloneRange();
    range.collapse(true);
    let node=range.startContainer, offset=range.startOffset, remaining=charIndex;
    while(node){
      if(node.nodeType===Node.TEXT_NODE){
        const len=node.length-offset;
        if(remaining<=len){
          const r=document.createRange();
          r.setStart(node,offset);
          r.setEnd(node,offset+remaining);
          const mark=document.createElement('span');
          mark.className='sstts-current';
          r.surroundContents(mark);
          return;
        } else {
          remaining-=len;
          offset=0;
        }
      }
      if(node.firstChild){
        node=node.firstChild;
      }else{
        while(node && !node.nextSibling) node=node.parentNode;
        if(node) node=node.nextSibling;
      }
      if(node && !lastRange.isPointInRange(node,0)) break;
    }
  }

  function clearSpokenHighlight(){
    document.querySelectorAll('span.sstts-current').forEach(el=>{
      const p=el.parentNode;
      while(el.firstChild) p.insertBefore(el.firstChild,el);
      p.removeChild(el);
      p.normalize();
    });
  }

  function updateButtons(state){
    const bar = document.getElementById(BAR_ID); if (!bar) return;
    const btn = q => bar.querySelector(`[data-act="${q}"]`);
    const set = (el, en) => { el.style.opacity = en ? '1' : '0.4'; el.style.pointerEvents = en ? 'auto' : 'none'; };

    const isPro = sstts_data?.is_paying_user;

    switch(state){
      case 'ready':
        set(btn('play'), true);

        


        if (!isPro) {
          // Executes for Free version
          btn('restart')?.remove();
          btn('pause')?.remove();
          btn('close')?.remove();
        }

        break;

      case 'speaking':
        set(btn('play'), false);
        
        break;

      case 'paused':
        set(btn('play'), true);
        
        break;

        case 'disabled': // Not really used in the version where everything is enabled
          set(btn('restart'), false);
          set(btn('play'), false);
          set(btn('pause'), false);
          set(btn('close'), true);  // Keep "close" active if needed
          break;

    }
  }


  // window.addEventListener('scroll', hideBar);
  document.addEventListener('keydown', e => {
    if (e.key === 'Escape') hideBar();
  });

})(); //  end of the IIFE