function mapVoiceTranscript(value) {
  const transcript = String(value || '').replace(/\s+/g, ' ').trim();
  if (!transcript) return {title:'', body:''};
  const sentence = transcript.match(/^(.+?[.!?])(?:\s+|$)(.*)$/);
  const title = (sentence ? sentence[1] : transcript).trim().slice(0, 255);
  const body = (sentence ? sentence[2] : '').trim().slice(0, 10000);
  return {title, body};
}

function createVoiceIssueCapture({
  Recognition, elements, createEvent = name => new Event(name, {bubbles:true}),
  transcriptStore = null, getLogin = () => '',
}) {
  const supported = typeof Recognition === 'function';
  const login = String(getLogin() || '').trim();
  const ready = supported && login && transcriptStore ? Promise.resolve(transcriptStore.load(login)).then(value => {
    const recovered = String(value || '').replace(/\s+/g, ' ').trim().slice(0, 10255);
    if (recovered) showReview(recovered, {persist:false, recovered:true});
  }) : Promise.resolve();
  elements.root.hidden = !supported;
  if (!supported) {
    elements.status.textContent = 'Voice capture is unavailable; type the title and note instead.';
    return {supported:false, ready, cancel() {}};
  }
  let recognition = null;

  function showReview(value, {persist = true, recovered = false} = {}) {
    elements.transcript.value = value;
    const activeLogin = String(getLogin() || '').trim();
    if (persist && activeLogin && transcriptStore) void transcriptStore.save(activeLogin, value);
    const hasDraft = Boolean(elements.title.value.trim() || elements.body.value.trim());
    elements.append.textContent = hasDraft ? 'Append to draft' : 'Use transcript';
    elements.replace.hidden = !hasDraft;
    elements.review.hidden = false;
    elements.status.textContent = recovered ?
      'Recovered transcript. Review it before using or discarding it.' :
      'Transcript ready. Review it before using it.';
  }

  elements.start.addEventListener('click', () => {
    recognition = new Recognition();
    recognition.continuous = true;
    recognition.interimResults = false;
    recognition.onresult = event => {
      const finalText = Array.from(event.results || [])
        .slice(event.resultIndex ?? 0)
        .filter(result => result.isFinal)
        .map(result => result[0]?.transcript || '').join(' ').replace(/\s+/g, ' ').trim();
      if (finalText) {
        const accumulated = [elements.transcript.value.trim(), finalText]
          .filter(Boolean).join(' ').replace(/\s+/g, ' ').trim().slice(0, 10255);
        showReview(accumulated);
      }
    };
    recognition.onerror = event => {
      elements.start.hidden = false;
      elements.stop.hidden = true;
      elements.status.textContent = event.error === 'not-allowed' || event.error === 'service-not-allowed' ?
        'Microphone permission was denied. Your draft and transcript are unchanged.' :
        'Voice capture stopped. Your draft and transcript are unchanged.';
    };
    recognition.onend = () => {
      elements.start.hidden = false;
      elements.stop.hidden = true;
    };
    try {
      recognition.start();
    } catch (_) {
      recognition = null;
      elements.start.hidden = false;
      elements.stop.hidden = true;
      elements.status.textContent = 'Voice capture could not start. Your draft and transcript are unchanged.';
      return;
    }
    elements.start.hidden = true;
    elements.stop.hidden = false;
    elements.status.textContent = 'Listening… Tap stop when you are finished.';
  });
  elements.stop.addEventListener('click', () => {
    recognition?.stop();
    elements.status.textContent = 'Finishing transcript…';
  });

  function clearCheckpoint() {
    const activeLogin = String(getLogin() || '').trim();
    if (activeLogin && transcriptStore) void transcriptStore.clear(activeLogin);
  }

  function commit(mode) {
    const mapped = mapVoiceTranscript(elements.transcript.value);
    if (mode === 'replace') {
      elements.title.value = mapped.title;
      elements.body.value = mapped.body;
    } else if (elements.title.value.trim()) {
      elements.body.value = [elements.body.value.trim(), mapped.title, mapped.body]
        .filter(Boolean).join('\n\n').slice(0, 10000);
    } else {
      elements.title.value = mapped.title;
      elements.body.value = [elements.body.value.trim(), mapped.body]
        .filter(Boolean).join('\n\n').slice(0, 10000);
    }
    elements.title.dispatchEvent(createEvent('input'));
    elements.body.dispatchEvent(createEvent('input'));
    clearCheckpoint();
    elements.review.hidden = true;
    elements.status.textContent = 'Transcript added. Review the title and note before saving.';
  }
  elements.append.addEventListener('click', () => commit('append'));
  elements.replace.addEventListener('click', () => commit('replace'));
  elements.discard?.addEventListener('click', () => {
    clearCheckpoint();
    elements.transcript.value = '';
    elements.review.hidden = true;
    elements.status.textContent = 'Recovered transcript discarded.';
  });

  return {supported:true, ready, cancel() { recognition?.abort(); recognition = null; }};
}

if (typeof module !== 'undefined') module.exports = {mapVoiceTranscript, createVoiceIssueCapture};
