// ── Constants ─────────────────────────────────────────────────────────────────
const MAX_RECORD_SECONDS = 30;
const MAX_RECORD_WORDS   = 60;
const EXT_MAP = { 'audio/webm': 'webm', 'audio/ogg': 'ogg', 'audio/mp4': 'm4a', 'audio/mpeg': 'mp3' };

// ── State ─────────────────────────────────────────────────────────────────────
const state = {
  level: 'B1',
  currentTopic: null,
  currentIndex: 0,
  questionQueue: [],
  transcript: '',
  isRecording: false,
  isChecking: false,
  sessionHistory: [],
};

// ── DOM refs ──────────────────────────────────────────────────────────────────
const screens = {
  topics:   document.getElementById('screen-topics'),
  practice: document.getElementById('screen-practice'),
  done:     document.getElementById('screen-done'),
};

const topicGrid      = document.getElementById('topic-grid');
const topicLabel     = document.getElementById('topic-label');
const progressFill   = document.getElementById('progress-fill');
const progressText   = document.getElementById('progress-text');
const questionText   = document.getElementById('question-text');
const transcriptBox  = document.getElementById('transcript-box');
const feedbackBox    = document.getElementById('feedback-box');
const feedbackContent= document.getElementById('feedback-content');
const recordBtn      = document.getElementById('record-btn');
const recordHint     = document.getElementById('record-hint');
const speakBtn       = document.getElementById('speak-btn');
const checkBtn       = document.getElementById('check-btn');
const clearBtn       = document.getElementById('clear-btn');
const downloadBtn    = document.getElementById('download-btn');
const skipBtn        = document.getElementById('skip-btn');
const nextActions    = document.getElementById('next-actions');
const nextBtn        = document.getElementById('next-btn');
const backBtn        = document.getElementById('back-btn');
const historySection = document.getElementById('history-section');
const historyList    = document.getElementById('history-list');

// ── Navigation ────────────────────────────────────────────────────────────────
function showScreen(name) {
  Object.values(screens).forEach(s => s.classList.remove('active'));
  screens[name].classList.add('active');
}

// ── Level selector ────────────────────────────────────────────────────────────
document.querySelectorAll('.level-btn').forEach(btn => {
  btn.addEventListener('click', () => {
    document.querySelectorAll('.level-btn').forEach(b => b.classList.remove('active'));
    btn.classList.add('active');
    state.level = btn.dataset.level;
  });
});

// ── Topic grid ────────────────────────────────────────────────────────────────
function buildTopicGrid() {
  TOPICS.forEach(topic => {
    const card = document.createElement('div');
    card.className = 'topic-card';
    card.innerHTML = `<div class="topic-icon">${topic.icon}</div><h3>${topic.name}</h3><p>${topic.desc}</p>`;
    card.addEventListener('click', () => startTopic(topic));
    topicGrid.appendChild(card);
  });
}

function startTopic(topic) {
  state.currentTopic = topic;
  state.sessionHistory = [];
  const indices = topic.questions.map((_, i) => i);
  for (let i = indices.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [indices[i], indices[j]] = [indices[j], indices[i]];
  }
  state.questionQueue = indices;
  renderHistoryList();
  showScreen('practice');
  loadQuestion();
}

// ── Questions ─────────────────────────────────────────────────────────────────
function loadQuestion() {
  const topic = state.currentTopic;
  state.currentIndex = state.questionQueue[0];
  const total = topic.questions.length;
  const done  = total - state.questionQueue.length;

  topicLabel.textContent       = `${topic.icon} ${topic.name}`;
  progressFill.style.width     = `${(done / total) * 100}%`;
  progressText.textContent     = `${done + 1} / ${total}`;
  questionText.textContent     = topic.questions[state.currentIndex];

  resetPracticeUI();
  autoSpeak();
}

function resetPracticeUI() {
  state.transcript = '';
  transcriptBox.contentEditable = 'false';
  updateTranscriptBox('');
  feedbackBox.classList.remove('visible');
  feedbackContent.innerHTML = '';
  nextActions.style.display = 'none';
  checkBtn.disabled    = true;
  skipBtn.disabled     = false;
  downloadBtn.disabled = true;
  audioBlob = null;
  stopRecording();
}

// ── Audio playback ────────────────────────────────────────────────────────────
let audioPlayer = null;

function stopAudio() {
  if (audioPlayer) { audioPlayer.pause(); audioPlayer = null; }
  speakBtn.classList.remove('speaking');
}

function autoSpeak() {
  stopAudio();
  const { id } = state.currentTopic;
  audioPlayer = new Audio(`audio/${id}_${state.currentIndex}.mp3`);
  speakBtn.classList.add('speaking');
  audioPlayer.onended = stopAudio;
  audioPlayer.onerror = stopAudio;
  audioPlayer.play();
}

speakBtn.addEventListener('click', () => {
  if (audioPlayer && !audioPlayer.paused) { stopAudio(); return; }
  autoSpeak();
});

// ── Speech recognition ────────────────────────────────────────────────────────
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
let recognition = null;

function initRecognition() {
  if (!SpeechRecognition) return null;
  const r = new SpeechRecognition();
  r.lang = 'de-DE';
  r.continuous = true;
  r.interimResults = true;
  r.maxAlternatives = 1;

  let finalText = '';

  r.onstart = () => {
    finalText = state.transcript;
    recordBtn.classList.add('recording');
    recordHint.textContent = 'Tippen zum Stoppen';
    state.isRecording = true;
  };

  r.onresult = (e) => {
    let interim = '';
    for (let i = e.resultIndex; i < e.results.length; i++) {
      if (e.results[i].isFinal) {
        finalText += (finalText ? ' ' : '') + e.results[i][0].transcript;
      } else {
        interim += e.results[i][0].transcript;
      }
    }
    const display = finalText + (interim ? (finalText ? ' ' : '') + interim : '');
    if (display.trim().split(/\s+/).length >= MAX_RECORD_WORDS) {
      stopRecording();
      return;
    }
    updateTranscriptBox(display);
    state.transcript = display;
    checkBtn.disabled = !display.trim();
  };

  r.onend = () => {
    if (state.isRecording) {
      // Android stops recognition on its own after silence — restart it
      try { r.start(); } catch (_) {}
    }
  };
  r.onerror = (e) => { if (e.error !== 'no-speech') stopRecording(); };

  return r;
}

// ── MediaRecorder ─────────────────────────────────────────────────────────────
let recordingTimer = null;
let mediaRecorder  = null;
let audioChunks    = [];
let audioBlob      = null;

async function startRecording() {
  if (!SpeechRecognition) {
    alert('Spracherkennung wird in diesem Browser nicht unterstützt. Bitte nutze Chrome oder Edge.');
    return;
  }
  stopAudio();
  audioBlob = null;
  audioChunks = [];
  downloadBtn.disabled = true;

  // Start SpeechRecognition first — triggers mic permission dialog on Android
  transcriptBox.contentEditable = 'false';
  recognition = initRecognition();
  state.isRecording = true;
  try { recognition.start(); } catch (_) {}

  clearTimeout(recordingTimer);
  recordingTimer = setTimeout(stopRecording, MAX_RECORD_SECONDS * 1000);

  // MediaRecorder for audio download — desktop only; on mobile it conflicts with SpeechRecognition
  const isMobile = /Android|iPhone|iPad/i.test(navigator.userAgent);
  if (!isMobile) {
    try {
      const stream   = await navigator.mediaDevices.getUserMedia({ audio: true });
      const mimeType = MediaRecorder.isTypeSupported('audio/webm;codecs=opus')
        ? 'audio/webm;codecs=opus' : 'audio/webm';
      mediaRecorder = new MediaRecorder(stream, { mimeType });
      mediaRecorder.ondataavailable = e => { if (e.data.size > 0) audioChunks.push(e.data); };
      mediaRecorder.onstop = () => {
        audioBlob = new Blob(audioChunks, { type: mimeType });
        stream.getTracks().forEach(t => t.stop());
        if (audioBlob.size > 0) downloadBtn.disabled = false;
      };
      mediaRecorder.start();
    } catch (e) {
      console.warn('MediaRecorder unavailable:', e);
    }
  }
}

function stopRecording() {
  clearTimeout(recordingTimer);
  state.isRecording = false;
  if (recognition) {
    try { recognition.stop(); } catch (_) {}
    recognition = null;
  }
  if (mediaRecorder && mediaRecorder.state !== 'inactive') {
    mediaRecorder.stop();
    mediaRecorder = null;
  }
  recordBtn.classList.remove('recording');
  recordHint.textContent = 'Tippen zum Aufnehmen';
  transcriptBox.contentEditable = 'true';
}

recordBtn.addEventListener('click', () => state.isRecording ? stopRecording() : startRecording());

// ── Transcript box ────────────────────────────────────────────────────────────
function updateTranscriptBox(text) {
  transcriptBox.textContent = text;
  transcriptBox.classList.toggle('empty', !text);
}

transcriptBox.addEventListener('input', () => {
  state.transcript = transcriptBox.textContent.trim();
  checkBtn.disabled = !state.transcript;
});

// ── Download recording ────────────────────────────────────────────────────────
downloadBtn.addEventListener('click', () => {
  if (!audioBlob) return;
  const topic    = (state.currentTopic?.name || 'antwort').replace(/[^\w]/g, '_');
  const now      = new Date();
  const ext      = EXT_MAP[audioBlob.type.split(';')[0]] || 'webm';
  const ms5 = String(Date.now()).slice(-5);
  const filename = `${topic}_q${state.currentIndex + 1}_${now.getDate()}-${now.getMonth() + 1}_${ms5}.${ext}`;
  const url = URL.createObjectURL(audioBlob);
  const a = document.createElement('a');
  a.href = url; a.download = filename; a.click();
  URL.revokeObjectURL(url);
});

// ── Clear ─────────────────────────────────────────────────────────────────────
clearBtn.addEventListener('click', () => {
  stopRecording();
  state.transcript = '';
  transcriptBox.contentEditable = 'false';
  updateTranscriptBox('');
  checkBtn.disabled = true;
  feedbackBox.classList.remove('visible');
  nextActions.style.display = 'none';
});

// ── Check answer ──────────────────────────────────────────────────────────────
checkBtn.addEventListener('click', async () => {
  const answer = state.transcript.trim();
  if (!answer || state.isChecking) return;

  stopRecording();
  state.isChecking = true;
  checkBtn.disabled = true;
  feedbackBox.classList.add('visible');
  feedbackContent.innerHTML = '<div class="loading-dots"><span></span><span></span><span></span></div>';

  try {
    const res  = await authFetch('api/check', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        question: state.currentTopic.questions[state.currentIndex],
        answer,
        level: state.level,
      }),
    });
    const data = await res.json();
    if (!res.ok) throw new Error(data.error || 'Fehler');

    feedbackContent.innerHTML = simpleMarkdown(data.feedback || '');
    state.sessionHistory.push({ question: state.currentTopic.questions[state.currentIndex], answer, feedback: data.feedback });
    renderHistoryList();
  } catch (err) {
    feedbackContent.innerHTML = `<span style="color:var(--danger)">Fehler: ${err.message}</span>`;
  } finally {
    state.isChecking = false;
    nextActions.style.display = 'flex';
    skipBtn.disabled = true;
  }
});

// ── Markdown renderer ─────────────────────────────────────────────────────────
function simpleMarkdown(text) {
  return text
    .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
    .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
    .replace(/\*(.+?)\*/g,     '<em>$1</em>')
    .replace(/`(.+?)`/g,       '<code>$1</code>')
    .replace(/^#{1,3} (.+)$/gm,'<h3>$1</h3>')
    .replace(/^\d+\. (.+)$/gm, '<li>$1</li>')
    .replace(/^[-•] (.+)$/gm,  '<li>$1</li>')
    .replace(/(<li>.*<\/li>\n?)+/g, m => `<ul>${m}</ul>`)
    .replace(/\n{2,}/g, '</p><p>')
    .replace(/\n/g, '<br>')
    .replace(/^(.+)$/, '<p>$1</p>');
}

// ── Skip / Retry / Next / Done ────────────────────────────────────────────────
skipBtn.addEventListener('click', () => {
  stopRecording(); stopAudio();
  state.questionQueue.shift();
  state.questionQueue.length === 0 ? showDone() : loadQuestion();
});

document.getElementById('retry-btn').addEventListener('click', () => { resetPracticeUI(); autoSpeak(); });

nextBtn.addEventListener('click', () => {
  state.questionQueue.shift();
  state.questionQueue.length === 0 ? showDone() : loadQuestion();
});

function showDone() {
  document.getElementById('stat-answered').textContent = state.sessionHistory.length;
  document.getElementById('stat-level').textContent    = state.level;
  progressFill.style.width = '100%';
  showScreen('done');
}

backBtn.addEventListener('click', () => { stopRecording(); stopAudio(); showScreen('topics'); });
document.getElementById('restart-btn').addEventListener('click', () => showScreen('topics'));

// ── History ───────────────────────────────────────────────────────────────────
function renderHistoryList() {
  historySection.classList.toggle('has-items', state.sessionHistory.length > 0);
  historyList.innerHTML = '';
  [...state.sessionHistory].reverse().forEach(item => {
    const el = document.createElement('div');
    el.className = 'history-item';
    el.innerHTML = `<div class="hi-q">F: ${escapeHtml(item.question)}</div><div class="hi-a">A: ${escapeHtml(item.answer)}</div>`;
    el.addEventListener('click', () => {
      feedbackContent.innerHTML = simpleMarkdown(item.feedback);
      feedbackBox.classList.add('visible');
      feedbackBox.scrollIntoView({ behavior: 'smooth', block: 'start' });
    });
    historyList.appendChild(el);
  });
}

function escapeHtml(s) {
  return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

// ── Init ──────────────────────────────────────────────────────────────────────
buildTopicGrid();
