// INVYONE Stage-2 — 음성 컨트롤
// 시연자 발화 (한국어) → 키워드 매칭 → INVYONE_UI.select(id, type)
// Chrome/Edge 의 Web Speech API (webkitSpeechRecognition) 사용.
// HTTPS 또는 localhost 환경에서만 마이크 권한 허용 — 운영(siflex.invyone.com)은 OK.

(function (global) {
  const SR = global.SpeechRecognition || global.webkitSpeechRecognition;

  // 시연자 발화 → 컴포넌트 매핑 사전.
  // 한 발화 안에 키워드 하나라도 포함되면 매칭. 위 항목이 우선.
  const VOICE_MAP = [
    // 핵심 1번 설비 (= BW-A1, 원수 취수펌프 #1) — PT 가장 자주 호출
    { id: 'bw-a1', type: 'pump', kws: ['1번', '일번', '원수 취수', '취수 펌프', 'bw-a1', '비더블유 에이 1', '비더블유에이일'] },
    { id: 'bw-a2', type: 'pump', kws: ['2번', '이번', 'bw-a2', '비더블유 에이 2'] },

    // 시스템/모듈
    { id: 'uf-system', type: 'module', kws: ['유에프 시스템', 'uf 시스템'] },
    { id: 'uf-pump-a', type: 'pump',  kws: ['유에프 펌프', 'uf 펌프', '유에프', 'uf'] },
    { id: 'ro-system', type: 'module', kws: ['알오 시스템', 'ro 시스템', '역삼투'] },
    { id: 'ro-feed',   type: 'pump',   kws: ['알오 피드', 'ro feed', '알오', 'ro'] },
    { id: 'mbr-carb-l', type: 'module', kws: ['카본 카트리지', '카트리지', '카본'] },
    { id: 'mbr',       type: 'tank',   kws: ['엠비알', 'mbr'] },
    { id: 'cip-pump',  type: 'pump',   kws: ['씨아이피 펌프', 'cip 펌프'] },
    { id: 'cip-tank',  type: 'tank',   kws: ['씨아이피', 'cip'] },
    { id: 'air-blower', type: 'pump',  kws: ['에어 블로어', '에어블로어', '송풍기', '블로어'] },

    // 탱크
    { id: 'sand',          type: 'tank', kws: ['샌드', '모래', 'sand'] },
    { id: 'ac',            type: 'tank', kws: ['활성탄', '에이씨', 'ac'] },
    { id: 'raw',           type: 'tank', kws: ['원수 탱크', 'raw'] },
    { id: 'chem',          type: 'tank', kws: ['약품 탱크', '케미컬', '약품', 'chem'] },
    { id: 'water-filter',  type: 'tank', kws: ['정수', '워터 필터', '워터필터', 'water filter'] },
    { id: 'dp',            type: 'tank', kws: ['디피', 'dp'] },
    { id: 'regulating',    type: 'tank', kws: ['조정 탱크', '레귤레이팅', '조정'] },

    // 센서
    { id: 'do',   type: 'sensor', kws: ['디오', '용존 산소', '용존산소', 'do'] },
    { id: 'temp', type: 'sensor', kws: ['온도', '템프', 'temp'] },
    { id: 'tss',  type: 'sensor', kws: ['티에스에스', '부유물', 'tss'] },
    { id: 'ph',   type: 'sensor', kws: ['피에이치', 'ph'] },
  ];

  // ============================================================
  // 매칭 엔진
  // ============================================================
  function normalize(s) {
    return (s || '').toString().toLowerCase().replace(/\s+/g, ' ').trim();
  }

  function match(transcript) {
    const t = normalize(transcript);
    if (!t) return null;
    for (const entry of VOICE_MAP) {
      for (const kw of entry.kws) {
        if (t.includes(normalize(kw))) {
          return { id: entry.id, type: entry.type, matchedKeyword: kw };
        }
      }
    }
    return null;
  }

  // ============================================================
  // SpeechRecognition 래퍼
  // ============================================================
  let recog = null;
  let listening = false;

  function start() {
    if (!SR) {
      emitEvent('🎤 이 브라우저는 음성 인식 미지원 (Chrome/Edge 권장)', 'warn');
      return;
    }
    if (listening) return;

    recog = new SR();
    recog.lang = 'ko-KR';
    recog.continuous = true;
    recog.interimResults = true;
    recog.maxAlternatives = 1;

    recog.onstart = () => { listening = true; setBtn(true); setTranscript('듣는 중...'); };
    recog.onend   = () => { listening = false; setBtn(false); setTranscript(''); };
    recog.onerror = (ev) => emitEvent(`🎤 음성 에러: ${ev.error}`, 'warn');

    recog.onresult = (ev) => {
      let interim = '', finalText = '';
      for (let i = ev.resultIndex; i < ev.results.length; i++) {
        const r = ev.results[i];
        if (r.isFinal) finalText += r[0].transcript;
        else           interim   += r[0].transcript;
      }
      setTranscript(finalText || interim);
      if (finalText) handleFinal(finalText);
    };

    try { recog.start(); }
    catch (e) { emitEvent(`🎤 시작 실패: ${e.message}`, 'warn'); }
  }

  function stop()   { if (recog && listening) recog.stop(); }
  function toggle() { listening ? stop() : start(); }

  function handleFinal(text) {
    const m = match(text);
    if (!m) {
      emitEvent(`🎤 "${text.trim()}" — 매칭 실패`, 'warn');
      return;
    }
    emitEvent(`🎤 "${text.trim()}" → ${m.id} (${m.type}) [${m.matchedKeyword}]`, 'info');
    if (global.INVYONE_UI && global.INVYONE_UI.select) {
      global.INVYONE_UI.select(m.id, m.type);
    }
    flashTarget(m.id);
  }

  function flashTarget(compId) {
    const el = document.querySelector(`[data-comp-id="${compId}"]`);
    if (!el) return;
    el.classList.remove('voice-flash');
    void el.offsetWidth;  // reflow
    el.classList.add('voice-flash');
    setTimeout(() => el.classList.remove('voice-flash'), 1400);
  }

  function emitEvent(msg, level) {
    if (global.INVYONE_ENGINE && global.INVYONE_ENGINE.emitEvent) {
      global.INVYONE_ENGINE.emitEvent(msg, level || 'info');
    } else {
      console.log('[VOICE]', msg);
    }
  }

  // ============================================================
  // UI inject (사이드바 첫 번째 section 끝에 마이크 버튼 + transcript)
  // ============================================================
  function injectUi() {
    const sidebar = document.querySelector('.sidebar-section');
    if (!sidebar) return;
    if (document.getElementById('btn-voice')) return; // 중복 방지

    const wrap = document.createElement('div');
    wrap.className = 'voice-wrap';
    wrap.innerHTML = `
      <button id="btn-voice" class="voice-btn" title="음성 인식 켜기/끄기 (한국어)">
        <svg class="voice-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
          <rect x="9" y="2" width="6" height="12" rx="3"/>
          <path d="M5 11a7 7 0 0 0 14 0"/>
          <line x1="12" y1="18" x2="12" y2="22"/>
          <line x1="8" y1="22" x2="16" y2="22"/>
        </svg>
        <span class="voice-label">VOICE CONTROL</span>
        <span class="voice-status-dot" aria-hidden="true"></span>
      </button>
      <div id="voice-transcript" class="voice-transcript"></div>
    `;
    sidebar.appendChild(wrap);
    document.getElementById('btn-voice').addEventListener('click', toggle);
  }

  function setBtn(on) {
    const btn = document.getElementById('btn-voice');
    if (!btn) return;
    btn.classList.toggle('listening', on);
    const lbl = btn.querySelector('.voice-label');
    if (lbl) lbl.textContent = on ? 'LISTENING...' : 'VOICE CONTROL';
  }
  function setTranscript(text) {
    const el = document.getElementById('voice-transcript');
    if (el) el.textContent = text || '';
  }

  function init() {
    injectUi();
    if (!SR) {
      const btn = document.getElementById('btn-voice');
      if (btn) btn.disabled = true;
      setTranscript('미지원 브라우저');
    }
  }

  // 외부 노출 (디버그/콘솔용)
  global.INVYONE_VOICE = { start, stop, toggle, match, init, VOICE_MAP };

  // main.js 가 INVYONE_UI 노출한 후 init
  document.addEventListener('DOMContentLoaded', () => setTimeout(init, 150));
})(window);
