<template>
  <DialogWidget
    ref="dialog"
    :title="$t('socialnetwork.vocab.practice.title')"
    :show-close="false"
    :buttons="buttons"
    :modal="true"
    :isTitleTranslated="false"
    width="55em"
    height="32em"
    name="VocabPracticeDialog"
    display="flex"
  >
    <div class="layout">
      <div class="left">
        <div class="opts">
          <label class="chk">
            <input type="checkbox" v-model="allVocabs" @change="reloadPool" />
            {{ $t('socialnetwork.vocab.practice.allVocabs') }}
          </label>
          <label class="chk">
            <input type="checkbox" v-model="simpleMode" @change="onSimpleModeChanged" />
            {{ $t('socialnetwork.vocab.practice.simple') }}
          </label>
        </div>

        <div v-if="loading">{{ $t('general.loading') }}</div>
        <div v-else-if="pool.length === 0">
          {{ $t('socialnetwork.vocab.practice.noPool') }}
        </div>
        <div v-else>
          <div class="prompt">
            <div class="dir">{{ directionLabel }}</div>
            <div class="word">{{ currentPrompt }}</div>
          </div>

          <div v-if="answered" class="feedback" :class="{ ok: lastCorrect, bad: !lastCorrect }">
            <div v-if="lastCorrect">{{ $t('socialnetwork.vocab.practice.correct') }}</div>
            <div v-else>
              {{ $t('socialnetwork.vocab.practice.wrong') }}
              <div class="answers">
                <div class="answersTitle">{{ $t('socialnetwork.vocab.practice.acceptable') }}</div>
                <ul>
                  <li v-for="a in acceptableAnswers" :key="a">{{ a }}</li>
                </ul>
              </div>
            </div>
          </div>

          <div v-if="!answered" class="answerArea">
            <div v-if="simpleMode" class="choices">
              <button
                v-for="opt in choiceOptions"
                :key="opt"
                class="choiceBtn"
                :disabled="locked"
                @click="submitChoice(opt)"
              >
                {{ opt }}
              </button>
            </div>
            <div v-else class="typing">
              <input
                ref="answerInput"
                v-model="typedAnswer"
                type="text"
                :disabled="locked"
                @keydown.enter.prevent="submitTyped"
              />
              <button :disabled="locked || typedAnswer.trim().length === 0" @click="submitTyped">
                {{ $t('socialnetwork.vocab.practice.check') }}
              </button>
            </div>
          </div>

          <div class="controls">
            <button v-if="showNextButton" @click="next">
              {{ $t('socialnetwork.vocab.practice.next') }}
            </button>
            <button v-else-if="showSkipButton" @click="skip">
              {{ $t('socialnetwork.vocab.practice.skip') }}
            </button>
          </div>
        </div>
      </div>

      <div class="right">
        <div class="stat">
          <div class="statTitle">{{ $t('socialnetwork.vocab.practice.stats') }}</div>
          <div class="statRow">
            <span class="k">{{ $t('socialnetwork.vocab.practice.success') }}</span>
            <span class="v">{{ correctCount }} ({{ successPercent }}%)</span>
          </div>
          <div class="statRow">
            <span class="k">{{ $t('socialnetwork.vocab.practice.fail') }}</span>
            <span class="v">{{ wrongCount }} ({{ failPercent }}%)</span>
          </div>
        </div>
      </div>
    </div>
  </DialogWidget>
</template>

<script>
import DialogWidget from '@/components/DialogWidget.vue';
import apiClient from '@/utils/axios.js';

export default {
  name: 'VocabPracticeDialog',
  components: { DialogWidget },
  data() {
    return {
      openParams: null, // { languageId, chapterId }
      onClose: null,
      loading: false,
      allVocabs: false,
      simpleMode: false,
      pool: [],

      // session stats
      correctCount: 0,
      wrongCount: 0,
      perId: {}, // { [id]: { c, w, streak, lastAsked } }
      lastIds: [],

      // current question
      current: null, // { id, learning, reference }
      direction: 'L2R', // L2R: learning->reference, R2L: reference->learning
      acceptableAnswers: [],
      choiceOptions: [],
      typedAnswer: '',
      answered: false,
      lastCorrect: false,
      locked: false,
      autoAdvanceTimer: null,
    };
  },
  computed: {
    buttons() {
      return [{ text: this.$t('message.close'), action: this.close }];
    },
    totalCount() {
      return this.correctCount + this.wrongCount;
    },
    successPercent() {
      if (this.totalCount === 0) return 0;
      return Math.round((this.correctCount / this.totalCount) * 100);
    },
    failPercent() {
      if (this.totalCount === 0) return 0;
      return Math.round((this.wrongCount / this.totalCount) * 100);
    },
    currentPrompt() {
      if (!this.current) return '';
      return this.direction === 'L2R' ? this.current.learning : this.current.reference;
    },
    directionLabel() {
      return this.direction === 'L2R'
        ? this.$t('socialnetwork.vocab.practice.dirLearningToRef')
        : this.$t('socialnetwork.vocab.practice.dirRefToLearning');
    },
    showNextButton() {
      // Nur bei falscher Antwort auf "Weiter" warten
      return this.answered && !this.lastCorrect;
    },
    showSkipButton() {
      return !this.answered;
    },
  },
  methods: {
    open({ languageId, chapterId, onClose = null }) {
      if (this.autoAdvanceTimer) {
        clearTimeout(this.autoAdvanceTimer);
        this.autoAdvanceTimer = null;
      }
      this.openParams = { languageId, chapterId };
      this.onClose = typeof onClose === 'function' ? onClose : null;
      this.allVocabs = false;
      this.simpleMode = false;
      this.correctCount = 0;
      this.wrongCount = 0;
      this.perId = {};
      this.lastIds = [];
      this.pool = [];
      this.locked = false;
      this.resetQuestion();
      this.$refs.dialog.open();
      this.$nextTick(() => {
        document.addEventListener('keydown', this.handleKeyDown);
      });
      this.reloadPool();
    },
    close() {
      if (this.autoAdvanceTimer) {
        clearTimeout(this.autoAdvanceTimer);
        this.autoAdvanceTimer = null;
      }
      const cb = this.onClose;
      this.onClose = null;
      document.removeEventListener('keydown', this.handleKeyDown);
      this.$refs.dialog.close();
      try {
        if (cb) cb();
      } catch (_) {}
    },
    handleKeyDown(event) {
      // Enter soll bei "Weiter" (falsch beantwortet) funktionieren.
      // Im Tippmodus soll Enter weiterhin "Prüfen" auslösen (Input hat eigenen handler).
      if (event.key !== 'Enter' && event.keyCode !== 13) return;

      if (this.showNextButton) {
        event.preventDefault();
        this.next();
        return;
      }

      // Falls man im Tippmodus ist und der Fokus NICHT im Input liegt, erlauben wir Enter als "Prüfen".
      if (!this.answered && !this.simpleMode && !this.locked) {
        const tag = event.target?.tagName?.toLowerCase?.();
        if (tag !== 'input' && tag !== 'textarea') {
          event.preventDefault();
          this.submitTyped();
        }
      }
    },
    normalize(s) {
      return String(s || '')
        .trim()
        .toLowerCase()
        .replace(/\s+/g, ' ');
    },
    resetQuestion() {
      this.current = null;
      this.direction = Math.random() < 0.5 ? 'L2R' : 'R2L';
      this.acceptableAnswers = [];
      this.choiceOptions = [];
      this.typedAnswer = '';
      this.answered = false;
      this.lastCorrect = false;
      this.locked = false;
    },
    onSimpleModeChanged() {
      if (this.autoAdvanceTimer) {
        clearTimeout(this.autoAdvanceTimer);
        this.autoAdvanceTimer = null;
      }
      this.locked = false;
      this.answered = false;
      this.lastCorrect = false;
      this.typedAnswer = '';

      if (!this.pool || this.pool.length === 0) return;

      // Wenn wir aktuell keine Frage haben, sofort eine neue ziehen.
      if (!this.current) {
        this.next();
        return;
      }

      // Aktuelle Frage behalten, nur UI/Antwortmodus neu aufbauen
      const prompt = this.currentPrompt;
      this.acceptableAnswers = this.getAnswersForPrompt(prompt, this.direction);
      if (this.simpleMode) {
        this.buildChoices();
      } else {
        this.choiceOptions = [];
        this.$nextTick(() => this.$refs.answerInput?.focus?.());
      }
    },
    async reloadPool() {
      if (!this.openParams) return;
      this.loading = true;
      try {
        let res;
        if (this.allVocabs) {
          res = await apiClient.get(`/api/vocab/languages/${this.openParams.languageId}/vocabs`);
          this.pool = res.data?.vocabs || [];
        } else {
          res = await apiClient.get(`/api/vocab/chapters/${this.openParams.chapterId}/vocabs`);
          this.pool = res.data?.vocabs || [];
        }
      } catch (e) {
        console.error('Reload pool failed:', e);
        this.pool = [];
      } finally {
        this.loading = false;
        this.next();
      }
    },
    getAnswersForPrompt(prompt, direction) {
      const p = this.normalize(prompt);
      const answers = new Set();
      for (const item of this.pool) {
        const itemPrompt = direction === 'L2R' ? item.learning : item.reference;
        if (this.normalize(itemPrompt) === p) {
          const a = direction === 'L2R' ? item.reference : item.learning;
          answers.add(a);
        }
      }
      return Array.from(answers);
    },
    computeWeight(item) {
      const st = this.perId[item.id] || { c: 0, w: 0, streak: 0, lastAsked: 0 };
      let w = 1;
      w += st.w * 2.5;
      w *= Math.pow(0.7, st.c);
      if (st.streak > 0) {
        w *= Math.pow(0.8, st.streak);
      } else if (st.streak < 0) {
        w *= 1 + Math.min(5, Math.abs(st.streak));
      }
      if (this.lastIds.includes(item.id)) w *= 0.1;
      return Math.max(0.05, Math.min(50, w));
    },
    pickNextItem() {
      const items = this.pool;
      if (!items || items.length === 0) return null;
      const weights = items.map((it) => this.computeWeight(it));
      const sum = weights.reduce((a, b) => a + b, 0);
      let r = Math.random() * sum;
      for (let i = 0; i < items.length; i++) {
        r -= weights[i];
        if (r <= 0) return items[i];
      }
      return items[items.length - 1];
    },
    buildChoices() {
      const prompt = this.currentPrompt;
      const acceptable = this.getAnswersForPrompt(prompt, this.direction);
      this.acceptableAnswers = acceptable;

      const options = new Set();
      // 1) mindestens eine richtige Übersetzung
      options.add(acceptable[0] || (this.direction === 'L2R' ? this.current.reference : this.current.learning));
      // 2) weitere Übersetzungen (Mehrdeutigkeiten) fürs gleiche Wort
      for (const a of acceptable) {
        if (options.size >= 3) break;
        options.add(a);
      }
      // 3) Distraktoren aus anderen Wörtern
      const allAnswers = this.pool.map((it) => (this.direction === 'L2R' ? it.reference : it.learning));
      for (let i = 0; i < 50 && options.size < 4; i++) {
        const cand = allAnswers[Math.floor(Math.random() * allAnswers.length)];
        if (!acceptable.map(this.normalize).includes(this.normalize(cand))) {
          options.add(cand);
        }
      }

      const arr = Array.from(options);
      // shuffle
      for (let i = arr.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [arr[i], arr[j]] = [arr[j], arr[i]];
      }
      this.choiceOptions = arr;
    },
    async playSound(ok) {
      try {
        const audio = new Audio(ok ? '/sounds/success.mp3' : '/sounds/fail.mp3');
        await audio.play();
      } catch (_) {
        // ignore autoplay issues
      }
    },
    markResult(isCorrect) {
      this.answered = true;
      this.lastCorrect = isCorrect;
      if (isCorrect) this.correctCount += 1;
      else this.wrongCount += 1;

      const id = this.current?.id;
      if (!id) return;
      const st = this.perId[id] || { c: 0, w: 0, streak: 0, lastAsked: 0 };
      if (isCorrect) {
        st.c += 1;
        st.streak = st.streak >= 0 ? st.streak + 1 : 1;
      } else {
        st.w += 1;
        st.streak = st.streak <= 0 ? st.streak - 1 : -1;
      }
      st.lastAsked = Date.now();
      this.perId[id] = st;

      this.lastIds.unshift(id);
      this.lastIds = this.lastIds.slice(0, 3);
    },
    submitChoice(opt) {
      if (this.locked) return;
      const ok = this.acceptableAnswers.map(this.normalize).includes(this.normalize(opt));
      this.markResult(ok);
      this.playSound(ok);
      if (ok) {
        // Direkt weiter zur nächsten Frage (kein Klick nötig)
        this.locked = true;
        this.autoAdvanceTimer = setTimeout(() => {
          this.autoAdvanceTimer = null;
          this.next();
        }, 350);
      }
    },
    submitTyped() {
      if (this.locked) return;
      const ans = this.normalize(this.typedAnswer);
      const ok = this.acceptableAnswers.map(this.normalize).includes(ans);
      this.markResult(ok);
      this.playSound(ok);
      if (ok) {
        this.locked = true;
        this.autoAdvanceTimer = setTimeout(() => {
          this.autoAdvanceTimer = null;
          this.next();
        }, 350);
      }
    },
    skip() {
      this.next();
    },
    next() {
      if (this.autoAdvanceTimer) {
        clearTimeout(this.autoAdvanceTimer);
        this.autoAdvanceTimer = null;
      }
      if (!this.pool || this.pool.length === 0) {
        this.resetQuestion();
        return;
      }
      this.resetQuestion();
      this.current = this.pickNextItem();
      if (!this.current) return;
      const prompt = this.currentPrompt;
      this.acceptableAnswers = this.getAnswersForPrompt(prompt, this.direction);
      if (this.simpleMode) this.buildChoices();
      this.$nextTick(() => {
        if (!this.simpleMode) this.$refs.answerInput?.focus?.();
      });
    },
  },
};
</script>

<style scoped>
.layout {
  display: flex;
  gap: 16px;
  height: 100%;
}
.left {
  flex: 1;
  min-width: 0;
}
.right {
  width: 16em;
  border-left: 1px solid #ddd;
  padding-left: 12px;
}
.opts {
  display: flex;
  gap: 16px;
  margin-bottom: 10px;
}
.chk {
  display: inline-flex;
  gap: 6px;
  align-items: center;
}
.prompt {
  padding: 10px;
  background: #fff;
  border: 1px solid #ccc;
  margin-bottom: 10px;
}
.dir {
  color: #555;
  font-size: 0.9em;
}
.word {
  font-size: 1.8em;
  font-weight: bold;
}
.typing {
  display: flex;
  gap: 8px;
  align-items: center;
}
.typing input {
  flex: 1;
  padding: 6px;
}
.choices {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.choiceBtn {
  padding: 8px;
}
.controls {
  margin-top: 12px;
}
.feedback {
  padding: 10px;
  border: 1px solid #ccc;
  margin-bottom: 10px;
}
.feedback.ok {
  background: #e8ffe8;
  border-color: #7bbe55;
}
.feedback.bad {
  background: #ffecec;
  border-color: #d33;
}
.answersTitle {
  margin-top: 6px;
  font-weight: bold;
}
.statTitle {
  font-weight: bold;
  margin-bottom: 8px;
}
.statRow {
  display: flex;
  justify-content: space-between;
  margin-bottom: 6px;
}
.k {
  color: #333;
}
.v {
  font-weight: bold;
}
</style>


