// src/hooks/useTTS.ts
import { useCallback, useEffect, useMemo, useRef, useState } from "react";

// src/store/accessibilityStore.ts
import { create } from "zustand";
import { devtools, persist } from "zustand/middleware";
var DEFAULT_ACCESSIBILITY_PREFERENCES = {
  contrastMode: "normal",
  saturationMode: "normal",
  fontSize: 0,
  letterSpacing: 0,
  lineSpacing: 0,
  highlightLinks: false,
  pauseAnimations: false,
  bigCursor: false,
  dyslexiaFont: false,
  readingAid: "none",
  keyboardShortcut: true,
  colorBlindMode: "none" /* None */,
  ttsMode: "off",
  ttsRate: 1,
  ttsVoiceId: null,
  librasEnabled: false
};
var useAccessibilityStore = create()(
  devtools(
    persist(
      (set) => ({
        ...DEFAULT_ACCESSIBILITY_PREFERENCES,
        isPanelOpen: false,
        ttsStatus: "idle",
        setContrastMode: (contrastMode) => set({ contrastMode }),
        setSaturationMode: (saturationMode) => set({ saturationMode }),
        setFontSize: (fontSize) => set({ fontSize }),
        setLetterSpacing: (letterSpacing) => set({ letterSpacing }),
        setLineSpacing: (lineSpacing) => set({ lineSpacing }),
        setHighlightLinks: (highlightLinks) => set({ highlightLinks }),
        setPauseAnimations: (pauseAnimations) => set({ pauseAnimations }),
        setBigCursor: (bigCursor) => set({ bigCursor }),
        setDyslexiaFont: (dyslexiaFont) => set({ dyslexiaFont }),
        setReadingAid: (readingAid) => set({ readingAid }),
        setKeyboardShortcut: (keyboardShortcut) => set({ keyboardShortcut }),
        setColorBlindMode: (colorBlindMode) => set({ colorBlindMode }),
        setTTSMode: (ttsMode) => set({ ttsMode }),
        setTTSRate: (ttsRate) => set({ ttsRate }),
        setTTSVoiceId: (ttsVoiceId) => set({ ttsVoiceId }),
        setTTSStatus: (ttsStatus) => set({ ttsStatus }),
        setLibrasEnabled: (librasEnabled) => set({ librasEnabled }),
        resetPreferences: () => set({ ...DEFAULT_ACCESSIBILITY_PREFERENCES }),
        openPanel: () => set({ isPanelOpen: true }),
        closePanel: () => set({ isPanelOpen: false }),
        togglePanel: () => set((state) => ({ isPanelOpen: !state.isPanelOpen }))
      }),
      {
        name: "accessibility-store",
        // version 1: removeu `librasEnabled` da persistência (era custoso
        // recarregar VLibras a cada refresh). A migração limpa esse valor
        // de localStorages antigos para evitar auto-load surpresa.
        version: 1,
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- migrate works with arbitrary persisted shapes from older versions
        migrate: (persistedState) => {
          if (persistedState && typeof persistedState === "object" && "librasEnabled" in persistedState) {
            delete persistedState.librasEnabled;
          }
          return persistedState;
        },
        partialize: (state) => ({
          contrastMode: state.contrastMode,
          saturationMode: state.saturationMode,
          fontSize: state.fontSize,
          letterSpacing: state.letterSpacing,
          lineSpacing: state.lineSpacing,
          highlightLinks: state.highlightLinks,
          pauseAnimations: state.pauseAnimations,
          bigCursor: state.bigCursor,
          dyslexiaFont: state.dyslexiaFont,
          readingAid: state.readingAid,
          keyboardShortcut: state.keyboardShortcut,
          colorBlindMode: state.colorBlindMode,
          ttsRate: state.ttsRate,
          ttsVoiceId: state.ttsVoiceId
          // ttsMode e librasEnabled NÃO são persistidos:
          // - ttsMode: o leitor sempre começa desligado ao recarregar
          //   a página para evitar comportamento confuso
          // - librasEnabled: o VLibras é pesado (~MBs de assets); auto-
          //   carregar a cada refresh seria custoso e surpreendente. O
          //   usuário ativa explicitamente quando precisa.
        })
      }
    ),
    { name: "accessibility-store" }
  )
);

// src/components/AccessibilityWidget/tts/WebSpeechProvider.ts
var WebSpeechProvider = class {
  synth;
  currentUtterance = null;
  constructor(synth = getSynth()) {
    this.synth = synth;
  }
  isSupported() {
    return this.synth !== null;
  }
  async getVoices() {
    if (!this.synth) return [];
    const synth = this.synth;
    const collect = () => synth.getVoices().map((v) => ({
      id: v.voiceURI,
      name: v.name,
      lang: v.lang,
      isLocal: v.localService
    }));
    const initial = collect();
    if (initial.length > 0) return initial;
    return new Promise((resolve) => {
      const onChange = () => {
        synth.removeEventListener("voiceschanged", onChange);
        resolve(collect());
      };
      synth.addEventListener("voiceschanged", onChange);
      setTimeout(() => {
        synth.removeEventListener("voiceschanged", onChange);
        resolve(collect());
      }, 1500);
    });
  }
  speak(text, options = {}, events = {}) {
    if (!this.synth) {
      events.onError?.("S\xEDntese de voz n\xE3o dispon\xEDvel neste navegador.");
      return;
    }
    const trimmed = text.trim();
    if (!trimmed) return;
    this.synth.cancel();
    const utterance = new SpeechSynthesisUtterance(trimmed);
    utterance.rate = options.rate ?? 1;
    utterance.pitch = options.pitch ?? 1;
    const allVoices = this.synth.getVoices();
    let chosenVoice;
    if (options.voiceId) {
      chosenVoice = allVoices.find((v) => v.voiceURI === options.voiceId);
    } else if (options.lang) {
      chosenVoice = allVoices.find(
        (v) => v.lang.toLowerCase().startsWith(options.lang.toLowerCase())
      );
    }
    if (chosenVoice) {
      utterance.voice = chosenVoice;
      utterance.lang = chosenVoice.lang;
    }
    utterance.onstart = () => events.onStart?.();
    utterance.onend = () => {
      this.currentUtterance = null;
      events.onEnd?.();
    };
    utterance.onpause = () => events.onPause?.();
    utterance.onresume = () => events.onResume?.();
    utterance.onerror = (event) => {
      this.currentUtterance = null;
      events.onError?.(event.error || "Erro desconhecido na s\xEDntese.");
    };
    this.currentUtterance = utterance;
    this.synth.speak(utterance);
  }
  pause() {
    this.synth?.pause();
  }
  resume() {
    this.synth?.resume();
  }
  stop() {
    this.synth?.cancel();
    this.currentUtterance = null;
  }
};
var getSynth = () => {
  if (typeof globalThis === "undefined") return null;
  const synth = globalThis.speechSynthesis;
  return synth ?? null;
};

// src/hooks/useTTS.ts
var useTTS = (providerOverride) => {
  const setTTSStatus = useAccessibilityStore((s) => s.setTTSStatus);
  const ttsRate = useAccessibilityStore((s) => s.ttsRate);
  const ttsVoiceId = useAccessibilityStore((s) => s.ttsVoiceId);
  const provider = useMemo(
    () => providerOverride ?? new WebSpeechProvider(),
    [providerOverride]
  );
  const [voices, setVoices] = useState([]);
  const rateRef = useRef(ttsRate);
  const voiceIdRef = useRef(ttsVoiceId);
  rateRef.current = ttsRate;
  voiceIdRef.current = ttsVoiceId;
  const isActiveSpeakerRef = useRef(false);
  useEffect(() => {
    let mounted = true;
    if (provider.isSupported()) {
      provider.getVoices().then((list) => {
        if (mounted) setVoices(list);
      }).catch(() => void 0);
    }
    return () => {
      mounted = false;
      if (isActiveSpeakerRef.current) {
        provider.stop();
        setTTSStatus("idle");
        isActiveSpeakerRef.current = false;
      }
    };
  }, [provider, setTTSStatus]);
  const hasPortugueseVoice = voices.some(
    (v) => v.lang.toLowerCase().startsWith("pt")
  );
  const speak = useCallback(
    (text) => {
      isActiveSpeakerRef.current = true;
      provider.speak(
        text,
        {
          rate: rateRef.current,
          voiceId: voiceIdRef.current ?? void 0
          // Não fixamos `lang: 'pt-BR'` aqui — em sistemas sem voz pt-BR
          // instalada, o browser fica tentando achar uma e nunca emite
          // áudio. O provider usa o `voice.lang` quando há voz escolhida.
        },
        {
          onStart: () => setTTSStatus("speaking"),
          onEnd: () => {
            isActiveSpeakerRef.current = false;
            setTTSStatus("idle");
          },
          onPause: () => setTTSStatus("paused"),
          onResume: () => setTTSStatus("speaking"),
          onError: () => {
            isActiveSpeakerRef.current = false;
            setTTSStatus("idle");
          }
        }
      );
    },
    [provider, setTTSStatus]
  );
  const pause = useCallback(() => {
    provider.pause();
    setTTSStatus("paused");
  }, [provider, setTTSStatus]);
  const resume = useCallback(() => {
    provider.resume();
    setTTSStatus("speaking");
  }, [provider, setTTSStatus]);
  const stop = useCallback(() => {
    isActiveSpeakerRef.current = false;
    provider.stop();
    setTTSStatus("idle");
  }, [provider, setTTSStatus]);
  return {
    isSupported: provider.isSupported(),
    voices,
    hasPortugueseVoice,
    speak,
    pause,
    resume,
    stop
  };
};
export {
  useTTS
};
//# sourceMappingURL=index.mjs.map