// /home/jwfnsshf/v.centrx.eu/pwa/js/main.js

console.log('[PWA] main.js загружен и исполняется');

document.addEventListener('DOMContentLoaded', () => {
  console.log('[PWA] DOMContentLoaded — запускаем код');

  // 1. Список языков
  const LANGUAGES = [
    { code: 'bg', name: 'Български' }, { code: 'hr', name: 'Hrvatski' }, { code: 'cs', name: 'Čeština' },
    { code: 'da', name: 'Dansk' }, { code: 'nl', name: 'Nederlands' }, { code: 'en', name: 'English' },
    { code: 'et', name: 'Eesti' }, { code: 'fi', name: 'Suomi' }, { code: 'fr', name: 'Français' },
    { code: 'de', name: 'Deutsch' }, { code: 'el', name: 'Ελληνικά' }, { code: 'hu', name: 'Magyar' },
    { code: 'ga', name: 'Gaeilge' }, { code: 'it', name: 'Italiano' }, { code: 'lv', name: 'Latviešu' },
    { code: 'lt', name: 'Lietuvių' }, { code: 'mt', name: 'Malti' }, { code: 'pl', name: 'Polski' },
    { code: 'pt', name: 'Português' }, { code: 'ro', name: 'Română' }, { code: 'sk', name: 'Slovenčina' },
    { code: 'sl', name: 'Slovenščina' }, { code: 'es', name: 'Español' }, { code: 'sv', name: 'Svenska' },
    { code: 'ru', name: 'Русский' }, { code: 'uk', name: 'Українська' }
  ];

  // 2. Получаем session и side из глобальных переменных, установленных в session.php
  const sessionId = window.SESSION_ID || null;
  const mySide    = window.SIDE || null;   // SIDE = "A" или "B"
  if (!sessionId || (mySide !== 'A' && mySide !== 'B')) {
    document.body.innerHTML =
      '<div style="padding:2rem; font-family:Arial, sans-serif;">Ошибка: неверный session или side</div>';
    return;
  }

  // 3. Рендерим контейнер – без inline-стилей, за стили отвечает CSS
  const root = document.getElementById('root');

  root.innerHTML = `
    <div class="chat-header">
      <label for="selMyLang">Мой язык:</label>
      <select id="selMyLang"></select>
      <span id="currentLang" style="margin-left:1rem; font-weight:bold;"></span>
      <button id="btnToggleTTS" class="btn-tts" title="Toggle TTS">🔊</button>
      <div id="waitingOverlay" class="waiting-overlay">Выберите язык и ждём второго участника…</div>
    </div>
    <div class="chat-window" id="chatWindow"></div>
    <div class="chat-input">
      <textarea id="txtMsg" placeholder="Введите текст…" disabled></textarea>
      <button id="btnSend" disabled>➤</button>
    </div>
    <div class="fab-mic" id="fabMic" title="Нажмите и говорите">🎙</div>
  `;

  // 4. Кэшируем элементы
  const selMyLang = document.getElementById('selMyLang');
  const currentLangDisplay = document.getElementById('currentLang');
  const btnToggleTTS = document.getElementById('btnToggleTTS');
  const txtMsg = document.getElementById('txtMsg');
  const btnSend = document.getElementById('btnSend');
  const chatW = document.getElementById('chatWindow');
  const fabMic = document.getElementById('fabMic');
  const waitingOverlay = document.getElementById('waitingOverlay');

  // Изначально поле для языка пустое
  currentLangDisplay.textContent = '';

  // 5. Состояния приложения
  let ttsEnabled = true;
  let isRecording = false;
  let recorder = null;
  let audioChunks = [];
  let activeAudio = null;
  let audioStream = null;
  let myLang = null;
  let partnerLang = null;
  let bothRegistered = false;
  let lastMessageId = 0;
  let pollingInterval = null;

  // 6. Проверка платформы
  const isIOS =
    /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;

  // 7. Заполняем dropdown «Мой язык»
  LANGUAGES.forEach((l) => {
    selMyLang.add(new Option(l.name, l.code));
  });
  selMyLang.value = '';

  // 8. Toggle TTS
  btnToggleTTS.addEventListener('click', () => {
    ttsEnabled = !ttsEnabled;
    btnToggleTTS.textContent = ttsEnabled ? '🔊' : '🔇';
  });

  // 9. Обработчик изменения «Моего языка»
  selMyLang.addEventListener('change', onMyLangChange);

  function blockUI(message) {
    waitingOverlay.textContent = message;
    waitingOverlay.style.display = 'flex';
    txtMsg.disabled = true;
    btnSend.disabled = true;
    fabMic.style.pointerEvents = 'none';
    fabMic.style.opacity = '0.3';
  }

  function unblockUI() {
    waitingOverlay.style.display = 'none';
    txtMsg.disabled = false;
    btnSend.disabled = true; // пока нет текста
    fabMic.style.pointerEvents = '';
    fabMic.style.opacity = '';
  }

  function appendMsg(text, cls) {
    const div = document.createElement('div');
    div.className = `chat-message ${cls}`;
    div.textContent = text;
    chatW.appendChild(div);
    div.scrollIntoView({ behavior: 'smooth' });
    return div;
  }

  async function onMyLangChange() {
    myLang = selMyLang.value;
    if (!myLang) return;

    blockUI('Ждём второго участника…');

    try {
      const res = await fetch('/register_language.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          session: sessionId,
          side:    mySide,
          lang:    myLang
        })
      });
      const data = await res.json();
      bothRegistered = data.bothRegistered;
      partnerLang = data.partnerLang;

      if (!bothRegistered) {
        currentLangDisplay.textContent = myLang.toUpperCase();
        blockUI('Ждём, пока второй участник выберет язык…');
      } else {
        currentLangDisplay.textContent = myLang.toUpperCase() + ' ↔ ' + partnerLang.toUpperCase();
        unblockUI();
        startPolling();
      }
    } catch (err) {
      console.error('Ошибка сети при регистрации языка:', err);
      appendMsg('Ошибка сети при регистрации языка', 'system');
    }
  }

  // 10. Polling: раз в 1.5 секунды запрашиваем новые сообщения и языки
  async function pollMessages() {
    try {
      const res = await fetch(
        `/get_messages.php?session=${encodeURIComponent(
          sessionId
        )}&last_id=${lastMessageId}`
      );
      if (!res.ok) throw new Error('Ошибка сервера');
      const data = await res.json();
      // data = { languages: { A: "...", B: "..." }, messages: [ ... ] }

      // 10.1. Обновляем partnerLang, если спарсились новые языки
      const newLangA = data.languages.A;
      const newLangB = data.languages.B;
      const freshPartner = (mySide === 'A' ? newLangB : newLangA);
      if (freshPartner && freshPartner !== partnerLang) {
        partnerLang = freshPartner;
        currentLangDisplay.textContent = myLang.toUpperCase() + ' ↔ ' + partnerLang.toUpperCase();
      }

      // 10.2. Затем проходим по массиву новых сообщений
      for (const msg of data.messages) {
        if (msg.from !== mySide) {
          appendMsg(msg.text, 'partner');
          if (ttsEnabled && msg.audio) {
            const byteCharacters = atob(msg.audio);
            const byteNumbers = new Array(byteCharacters.length);
            for (let i = 0; i < byteCharacters.length; i++) {
              byteNumbers[i] = byteCharacters.charCodeAt(i);
            }
            const byteArray = new Uint8Array(byteNumbers);
            const blob = new Blob([byteArray], { type: 'audio/mpeg' });

            if (activeAudio) {
              activeAudio.pause();
              URL.revokeObjectURL(activeAudio.src);
              activeAudio = null;
            }
            const url = URL.createObjectURL(blob);
            const audio = new Audio(url);
            activeAudio = audio;
            audio.play().catch((e) =>
              console.error('Ошибка воспроизведения:', e)
            );
            audio.onended = () => {
              URL.revokeObjectURL(url);
              if (activeAudio === audio) activeAudio = null;
            };
            audio.onerror = () => {
              URL.revokeObjectURL(url);
              if (activeAudio === audio) activeAudio = null;
            };
          }
        }
        lastMessageId = Math.max(lastMessageId, msg.id);
      }
    } catch (e) {
      console.error('pollMessages error:', e);
    }
  }

  function startPolling() {
    pollMessages();
    pollingInterval = setInterval(pollMessages, 1500);
  }

  // 11. Отправка текста → перевод → TTS → post_message.php
  txtMsg.addEventListener('input', () => {
    btnSend.disabled = !txtMsg.value.trim();
  });

  btnSend.addEventListener('click', () => {
    const text = txtMsg.value.trim();
    if (!text || !bothRegistered) return;
    handleUserText(text);
    txtMsg.value = '';
    btnSend.disabled = true;
  });

  async function handleUserText(text) {
    appendMsg(text, 'driver');

    try {
      const translation = await translateOnline(text, myLang, partnerLang);

      let ttsBlob = null;
      if (ttsEnabled) {
        try {
          const resTTS = await fetch('/api/tts.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ text: translation, lang: partnerLang }),
          });
          if (resTTS.ok) {
            ttsBlob = await resTTS.blob();
          }
        } catch (ttsError) {
          console.error('TTS error у отправителя:', ttsError);
        }
      }

      let audioB64 = '';
      if (ttsBlob) {
        const arrayBuffer = await ttsBlob.arrayBuffer();
        const bytes = new Uint8Array(arrayBuffer);
        let binary = '';
        for (let b of bytes) binary += String.fromCharCode(b);
        audioB64 = btoa(binary);
      }

      const res = await fetch('/post_message.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          session: sessionId,
          from: mySide,
          text: translation,
          audio: audioB64,
        }),
      });
      const respData = await res.json();
      if (!respData.id) {
        console.error('Ошибка post_message:', respData.error);
      } else {
        lastMessageId = Math.max(lastMessageId, respData.id);
      }
    } catch (e) {
      console.error('Ошибка при отправке сообщения:', e);
      appendMsg('Ошибка при переводе или отправке', 'system');
    }
  }

  // 12. API-функции (translate)
  async function translateOnline(text, source, target) {
    const res = await fetch('/api/translate.php', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ text, source, target }),
    });
    if (!res.ok) {
      const error = await res.text();
      throw new Error(error || res.statusText);
    }
    const data = await res.json();
    return data.translation;
  }

  // (speakText оставляем для других вызовов, если понадобятся)
  async function speakText(text, code) {
    if (activeAudio) {
      activeAudio.pause();
      URL.revokeObjectURL(activeAudio.src);
      activeAudio = null;
    }

    const res = await fetch('/api/tts.php', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ text, lang: code }),
    });

    if (!res.ok) {
      const error = await res.text();
      throw new Error(error || 'TTS error');
    }

    const blob = await res.blob();
    const url = URL.createObjectURL(blob);
    const audio = new Audio(url);
    activeAudio = audio;

    audio.play().catch((e) => {
      console.error('Ошибка воспроизведения:', e);
      appendMsg('Ошибка воспроизведения: нужен жест пользователя', 'system');
    });

    audio.onended = () => {
      URL.revokeObjectURL(url);
      if (activeAudio === audio) activeAudio = null;
    };
    audio.onerror = () => {
      URL.revokeObjectURL(url);
      if (activeAudio === audio) activeAudio = null;
    };

    return blob;
  }

  // 13. STT (аналогично оригинальному коду)
  function setupVoiceRecording() {
    fabMic.addEventListener('contextmenu', (e) => {
      e.preventDefault();
      return false;
    });
    fabMic.addEventListener('touchstart', handleTouchStart, {
      passive: false,
    });
    fabMic.addEventListener('touchmove', handleTouchMove, {
      passive: false,
    });
    fabMic.addEventListener('touchend', handleTouchEnd, {
      passive: false,
    });
    fabMic.addEventListener('touchcancel', handleTouchEnd, {
      passive: false,
    });
    if (!isIOS) {
      fabMic.addEventListener('mousedown', startRecording);
      fabMic.addEventListener('mouseup', stopRecording);
      fabMic.addEventListener('mouseleave', stopRecording);
    }
    if (isIOS) {
      fabMic.style.webkitTouchCallout = 'none';
      fabMic.style.webkitUserSelect = 'none';
      fabMic.style.userSelect = 'none';
      fabMic.style.touchAction = 'none';
      fabMic.style.cursor = 'pointer';
    }
  }

  function handleTouchStart(e) {
    e.preventDefault();
    e.stopPropagation();
    startRecording();
  }
  function handleTouchMove(e) {
    e.preventDefault();
    e.stopPropagation();
  }
  function handleTouchEnd(e) {
    e.preventDefault();
    e.stopPropagation();
    stopRecording();
  }

  async function startRecording() {
    if (!bothRegistered) return;
    if (isRecording) return;

    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      audioStream = stream;
      const formats = [
        { mime: 'audio/wav', ext: 'wav' },
        { mime: 'audio/mp4', ext: 'm4a' },
        { mime: 'audio/webm', ext: 'webm' },
        { mime: 'audio/ogg', ext: 'ogg' },
        { mime: 'audio/mpeg', ext: 'mp3' },
      ];
      let selected = null;
      for (const f of formats) {
        if (MediaRecorder.isTypeSupported(f.mime)) {
          selected = f;
          break;
        }
      }
      if (!selected) selected = { mime: '', ext: 'wav' };
      recorder = selected.mime
        ? new MediaRecorder(stream, { mimeType: selected.mime })
        : new MediaRecorder(stream);
      audioChunks = [];
      isRecording = true;
      recorder.ondataavailable = (e) => {
        if (e.data.size > 0) audioChunks.push(e.data);
      };
      recorder.onerror = (e) => {
        console.error('Recording error:', e.error);
        appendMsg('Ошибка записи', 'system');
        cleanupRecording();
      };
      recorder.onstop = async () => {
        console.log('[STT] Запись остановлена');
        try {
          if (audioChunks.length === 0) throw new Error('Нет аудиоданных');
          let mime = recorder.mimeType || 'audio/wav';
          let ext = 'wav';
          if (mime.includes('mp4') || mime.includes('m4a')) ext = 'm4a';
          else if (mime.includes('webm')) ext = 'webm';
          else if (mime.includes('ogg')) ext = 'ogg';
          else if (mime.includes('mpeg') || mime.includes('mp3')) ext = 'mp3';
          const blob = new Blob(audioChunks, { type: mime });
          const fd = new FormData();
          fd.append('file', blob, `voice.${ext}`);
          fd.append('lang', myLang);
          const sttMsg = appendMsg('(распознавание…)', 'client');
          const res = await fetch('/api/stt.php', { method: 'POST', body: fd });
          if (!res.ok) {
            let errorText = res.statusText;
            try {
              const d = await res.json();
              errorText = d.error || JSON.stringify(d);
            } catch {}
            throw new Error(errorText);
          }
          const data = await res.json();
          sttMsg.textContent = data.text;
          handleUserText(data.text);
        } catch (err) {
          console.error('[STT] Error:', err);
          appendMsg(`Ошибка распознавания: ${err.message}`, 'client');
        } finally {
          cleanupRecording();
        }
      };
      recorder.start();
      fabMic.classList.add('recording');
      console.log('[STT] Запись начата');
    } catch (err) {
      console.error('[STT] Microphone error:', err);
      appendMsg(`Ошибка микрофона: ${err.message}`, 'system');
      cleanupRecording();
    }
  }

  function stopRecording() {
    if (!isRecording) return;
    fabMic.classList.remove('recording');
    isRecording = false;
    if (recorder && recorder.state !== 'inactive') recorder.stop();
  }

  function cleanupRecording() {
    if (audioStream) {
      audioStream.getTracks().forEach((track) => track.stop());
      audioStream = null;
    }
    recorder = null;
    audioChunks = [];
    isRecording = false;
    fabMic.classList.remove('recording');
  }

  // 14. Инициализация STT
  if (window.MediaRecorder) {
    setupVoiceRecording();
  } else {
    fabMic.style.opacity = 0.3;
    fabMic.title = 'Голосовой ввод не поддерживается';
  }

  console.log('[PWA] Приложение инициализировано');
});
