'use strict';
/* ──────────────────────────────────────────────────────────────────
   TaskCard component — reusable across variants / practice / topic /
   mock views. Renders ONE task with answer input, check button, and
   solution toggle.

   Public API:
     EP.TaskCard.render(container, task, opts)
       container : HTMLElement
       task      : { id, idx, type, text, figure, opts, answer, solution }
       opts      : {
         mode             : 'variant'|'practice'|'topic'|'mock'
         sessionId        : number | null   (groups attempts in a session)
         autoCheck        : true            (whether check button + verdict UI is shown)
         showSolution     : true            (whether solution toggle exists)
         readonly         : false           (inputs disabled; for finished mock review)
         prefillAnswer    : string | null   (initial user_answer; for mock review)
         forceVerdict     : {isCorrect:0|1} | null (show verdict badge as if checked)
         onAnswerChange   : (taskId, value) => void  (per-keystroke, debounced; mock auto-save)
         onAttempt        : (result) => void  (notify parent after check or solution-view)
         numbering        : number | null   (override task number badge)
       }
   ────────────────────────────────────────────────────────────────── */

(function () {
  const ICONS = {
    chev:   '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>',
    check:  '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>',
    cross:  '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',
    rotate: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><polyline points="3 3 3 8 8 8"/></svg>',
  };

  function escapeHtml(s) {
    return String(s || '').replace(/[&<>"']/g, c => ({ '&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;', "'":'&#39;' }[c]));
  }

  /* topic_ref → "Учить тему" deep-link to the textbook chapter/paragraph.
     ref = { slug, paragraph, title }. Paragraph is null for hub links. */
  function buildRefLink(ref) {
    if (!ref || !ref.slug) return '';
    const href = ref.paragraph
      ? `/textbook/${encodeURIComponent(ref.slug)}#sec-p${ref.paragraph}`
      : `/textbook/${encodeURIComponent(ref.slug)}`;
    const label = ref.paragraph ? `§${ref.paragraph}` : 'учебник';
    const title = ref.title ? `Учить тему: ${escapeHtml(ref.title)}` : 'Перейти к материалу';
    return `<a class="tc-ref-btn" href="${href}" target="_blank" rel="noopener" title="${title}">
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
        <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
        <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
      </svg>
      <span>Учить тему · ${escapeHtml(label)}</span>
    </a>`;
  }

  function buildOptsBlock(taskId, opts) {
    const isLong = opts.some(([, t]) => t.length > 40 && !t.startsWith('$'));
    const cls = isLong ? 'tc-opts tc-opts-vertical' : 'tc-opts';
    const name = `tc-opt-${taskId}`;
    return `<div class="${cls}" data-tc-mc>` + opts.map(([l, t]) => `
      <label class="tc-opt">
        <input type="radio" name="${name}" value="${escapeHtml(l)}" />
        <span class="tc-opt-lbl">${escapeHtml(l)})</span>
        <span class="tc-opt-text">${t}</span>
      </label>
    `).join('') + `</div>`;
  }

  /* Render one task into `container`. Returns a controller object with .destroy(). */
  function render(container, task, opts = {}) {
    const mode      = opts.mode || 'variant';
    const autoCheck = opts.autoCheck !== false;
    const showSol   = opts.showSolution !== false;
    const readonly  = !!opts.readonly;
    const numbering = (opts.numbering != null) ? opts.numbering : task.idx;
    const sessionId = opts.sessionId || null;
    const onAttempt = opts.onAttempt || (() => {});
    const onAnswerChange = opts.onAnswerChange || null;

    const card = document.createElement('div');
    card.className = 'tc-card';
    card.dataset.taskId = String(task.id);
    card.dataset.taskType = task.type;

    // ── Build input area by task type × autoCheck combo
    let inputBlock = '';
    const verdictSlot = `<div class="tc-verdict" data-tc-verdict hidden></div>`;
    const checkBtnRow = autoCheck
      ? `<div class="tc-action-row">
           <button class="tc-check-btn" data-tc-check disabled>Проверить</button>
           ${verdictSlot}
         </div>`
      : verdictSlot;

    if (task.type === 'mc' && task.opts) {
      inputBlock = buildOptsBlock(task.id, task.opts) + checkBtnRow;
    } else if (task.type === 'open') {
      inputBlock = `
        <div class="tc-input-row">
          <label class="tc-ans-label">Ответ:</label>
          <input class="tc-ans-input" type="text" autocomplete="off" inputmode="text"
                 placeholder="например, 9/4 или -2" data-tc-text />
        </div>` + checkBtnRow;
    } else if (task.type === 'long' && autoCheck) {
      inputBlock = `
        <div class="tc-self-mark">
          <span class="tc-self-mark-label">Развёрнутый ответ — проверьте себя по решению, затем отметьте:</span>
          <div class="tc-self-mark-btns">
            <button class="tc-self-btn tc-self-yes" data-tc-self="1">${ICONS.check} Я решил</button>
            <button class="tc-self-btn tc-self-no"  data-tc-self="0">${ICONS.cross} Не решил</button>
          </div>
        </div>`;
    } else if (task.type === 'long' && !autoCheck) {
      // Mock + long: short free-text answer
      inputBlock = `
        <div class="tc-input-row">
          <label class="tc-ans-label">Ответ:</label>
          <input class="tc-ans-input" type="text" autocomplete="off" inputmode="text"
                 placeholder="кратко ваш ответ" data-tc-text />
        </div>` + verdictSlot;
    }

    const refLink = buildRefLink(task.topic_ref);
    const solBlock = (showSol && task.solution) ? `
      <div class="tc-sol-wrap">
        <div class="tc-sol-row">
          <button class="tc-sol-btn" data-tc-sol>${ICONS.chev}<span>Показать решение</span></button>
          ${refLink}
        </div>
        <div class="tc-sol-panel" data-tc-sol-panel>${task.solution}</div>
      </div>` : (refLink ? `<div class="tc-sol-wrap"><div class="tc-sol-row">${refLink}</div></div>` : '');

    card.innerHTML = `
      <div class="tc-head">
        <div class="tc-num">${numbering}</div>
        <div class="tc-num-label">Задание ${numbering}</div>
        <span class="tc-type-badge tc-type-${task.type}">${typeLabel(task.type)}</span>
      </div>
      <div class="tc-body">
        <div class="tc-text">${task.text}</div>
        ${task.figure ? `<div class="tc-figure">${task.figure}</div>` : ''}
        ${inputBlock}
      </div>
      ${solBlock}
    `;
    container.appendChild(card);

    // ── KaTeX render
    EP.katex?.run(card);

    // ── State
    let startedAt    = Date.now();
    let solutionLogged = false;
    let solutionRendered = false;
    let attemptCount = 0;       // how many CHECK attempts made
    let firstAttemptCorrect = null; // we report this in onAttempt

    // ── Prefill answer (mock review or resumed mock session)
    if (opts.prefillAnswer != null) {
      const text = card.querySelector('[data-tc-text]');
      if (text) text.value = String(opts.prefillAnswer);
      const radios = card.querySelectorAll('input[type="radio"]');
      radios.forEach(r => { if (r.value === String(opts.prefillAnswer)) r.checked = true; });
    }

    // ── Force verdict (mock review: server has graded; show result without check button)
    if (opts.forceVerdict && opts.forceVerdict.isCorrect != null) {
      applyVerdictReadonly(opts.forceVerdict.isCorrect);
    }

    // ── Readonly: disable all inputs (mock review)
    if (readonly) {
      card.querySelectorAll('input').forEach(el => el.disabled = true);
      card.dataset.tcLocked = '1';
    }

    // ── Input enable on first interaction + auto-save (mock)
    const inputs = card.querySelectorAll('input[type="radio"], [data-tc-text]');
    const checkBtn = card.querySelector('[data-tc-check]');
    let saveDebounce = null;
    inputs.forEach(inp => {
      inp.addEventListener('input',  () => { updateCheckEnabled(); maybeAutoSave(); });
      inp.addEventListener('change', () => { updateCheckEnabled(); maybeAutoSave(); });
    });
    function updateCheckEnabled() {
      if (!checkBtn) return;
      const has = readUserAnswer() !== null;
      checkBtn.disabled = !has || card.dataset.tcLocked === '1';
    }
    function maybeAutoSave() {
      if (!onAnswerChange || readonly) return;
      const v = readUserAnswer();
      // debounce per-keystroke text input; radio changes save immediately
      clearTimeout(saveDebounce);
      const delay = card.querySelector('input[type="radio"]:checked') ? 0 : 450;
      saveDebounce = setTimeout(() => onAnswerChange(task.id, v), delay);
    }

    function applyVerdictReadonly(isCorrect) {
      card.classList.add(isCorrect ? 'tc-correct' : 'tc-wrong');
      const verdict = card.querySelector('[data-tc-verdict]');
      if (verdict) {
        verdict.hidden = false;
        verdict.innerHTML = isCorrect
          ? `<span class="tc-verdict-ok">${ICONS.check} Правильно</span>`
          : `<span class="tc-verdict-bad">${ICONS.cross} Неправильно</span>`;
      }
    }

    function readUserAnswer() {
      const mcGroup = card.querySelector('[data-tc-mc]');
      if (mcGroup) {
        const picked = mcGroup.querySelector('input[type="radio"]:checked');
        return picked ? picked.value : null;
      }
      const text = card.querySelector('[data-tc-text]');
      if (text) {
        const v = text.value.trim();
        return v || null;
      }
      return null;
    }

    // ── Check action
    if (checkBtn) {
      checkBtn.addEventListener('click', () => {
        const userAnswer = readUserAnswer();
        if (userAnswer == null) return;
        const isCorrect = EP.answer.check(userAnswer, task.answer) ? 1 : 0;
        attemptCount++;
        if (firstAttemptCorrect === null) firstAttemptCorrect = isCorrect;
        applyVerdict(isCorrect, userAnswer);
        sendAttempt({ user_answer: userAnswer, is_correct: isCorrect });
        onAttempt({ taskId: task.id, isCorrect, userAnswer, attempt: attemptCount });
      });
    }

    function applyVerdict(isCorrect, userAnswer) {
      const verdict = card.querySelector('[data-tc-verdict]');
      card.classList.remove('tc-correct', 'tc-wrong');
      card.classList.add(isCorrect ? 'tc-correct' : 'tc-wrong');

      if (verdict) {
        verdict.hidden = false;
        verdict.innerHTML = isCorrect
          ? `<span class="tc-verdict-ok">${ICONS.check} Правильно</span>`
          : `<span class="tc-verdict-bad">${ICONS.cross} Неправильно</span>
             <button class="tc-retry-btn" data-tc-retry>${ICONS.rotate} Попробовать ещё</button>`;
      }

      if (isCorrect) {
        // Lock inputs + auto-open solution
        card.querySelectorAll('input').forEach(el => el.disabled = true);
        checkBtn.disabled = true;
        card.dataset.tcLocked = '1';
        autoOpenSolution();
      } else {
        // Allow retry
        const retry = card.querySelector('[data-tc-retry]');
        if (retry) retry.addEventListener('click', () => resetForRetry());
      }
    }

    function resetForRetry() {
      const verdict = card.querySelector('[data-tc-verdict]');
      card.classList.remove('tc-wrong');
      if (verdict) { verdict.hidden = true; verdict.innerHTML = ''; }
      startedAt = Date.now();
    }

    function autoOpenSolution() {
      const btn = card.querySelector('[data-tc-sol]');
      const panel = card.querySelector('[data-tc-sol-panel]');
      if (btn && panel && !panel.classList.contains('visible')) {
        toggleSolution(btn, panel);
      }
    }

    // ── Solution toggle (manual)
    const solBtn = card.querySelector('[data-tc-sol]');
    const solPanel = card.querySelector('[data-tc-sol-panel]');
    if (solBtn && solPanel) {
      solBtn.addEventListener('click', () => toggleSolution(solBtn, solPanel));
    }

    function toggleSolution(btn, panel) {
      const open = panel.classList.contains('visible');
      panel.classList.toggle('visible', !open);
      btn.classList.toggle('open', !open);
      btn.querySelector('span').textContent = open ? 'Показать решение' : 'Скрыть решение';
      if (!open) {
        if (!solutionRendered) {
          EP.katex?.run(panel);
          solutionRendered = true;
        }
        if (!solutionLogged) {
          solutionLogged = true;
          sendAttempt({ solution_viewed: 1 });
          onAttempt({ taskId: task.id, solutionViewed: true });
        }
      }
    }

    // ── Long: self-mark buttons
    card.querySelectorAll('[data-tc-self]').forEach(btn => {
      btn.addEventListener('click', () => {
        const val = btn.dataset.tcSelf === '1' ? 1 : 0;
        attemptCount++;
        if (firstAttemptCorrect === null) firstAttemptCorrect = val;
        card.classList.remove('tc-correct', 'tc-wrong');
        card.classList.add(val ? 'tc-correct' : 'tc-wrong');
        card.querySelectorAll('[data-tc-self]').forEach(b => b.disabled = true);
        sendAttempt({ is_correct: val });
        onAttempt({ taskId: task.id, isCorrect: val, attempt: attemptCount });
      });
    });

    function sendAttempt(partial) {
      const body = Object.assign({
        exam_task_id:   task.id,
        mode,
        session_id:     sessionId,
        time_ms:        Math.min(Date.now() - startedAt, 24 * 3600 * 1000),
        user_answer:    null,
        is_correct:     null,
        hint_used:      0,
        solution_viewed:0,
      }, partial);
      // Best-effort — UI doesn't block on this
      EP.api.saveAttempt(body).catch(() => {});
    }

    // ── Review mode: auto-open the solution panel for instant context
    if (opts.forceVerdict && showSol) {
      const sb = card.querySelector('[data-tc-sol]');
      const sp = card.querySelector('[data-tc-sol-panel]');
      if (sb && sp && !sp.classList.contains('visible')) {
        sp.classList.add('visible');
        sb.classList.add('open');
        sb.querySelector('span').textContent = 'Скрыть решение';
        EP.katex?.run(sp);
      }
    }

    return {
      el: card,
      destroy: () => card.remove(),
    };
  }

  function typeLabel(type) {
    if (type === 'mc')   return 'выбор';
    if (type === 'open') return 'кр. ответ';
    return 'развёрнут.';
  }

  window.EP = window.EP || {};
  window.EP.TaskCard = { render };
})();
