<script>
  /**
   * /study/cards-study — 암기카드 학습 (공부 암기노트 B3, 모바일 우선·아이폰 15 Pro Max 430×932).
   *
   * 두 트랙:
   *   1) 복습(SR)  — due 카드를 앞면 회상 → 탭 reveal → 3단 자기평가(모름/애매/암).
   *      backend: GET /study-cards/due · POST /study-cards/{id}/rate (암/애매/모름 → correct/unsure/wrong)
   *      '암'(correct) 버튼은 stage별 다음 복습일을 미리보기(+3/7/14일·졸업), 모름·애매는 내일.
   *   2) 그냥 공부(cram) — 검수 통과 카드를 덜 본 순서로 휙휙, '봤다'만 기록(SR 무관).
   *      backend: GET /study-cards/deck (format 필터) · POST /study-cards/{id}/view
   *
   * 검수(needs_review=false) 카드만 복습 큐 입고(백엔드 양층 게이트). 카드 format = qa/cloze 2종.
   * 데스크탑 키보드: Space=정답 보기 / 복습 J·K·L=모름·애매·암 / 그냥공부 Enter=봤다.
   */
  import { onMount } from 'svelte';
  import { goto } from '$app/navigation';
  import { api } from '$lib/api';
  import { addToast } from '$lib/stores/toast';
  import { ArrowLeft, Repeat, Layers, Eye, BookOpen, Flag } from 'lucide-svelte';
  import Button from '$lib/components/ui/Button.svelte';
  import Skeleton from '$lib/components/ui/Skeleton.svelte';
  import EmptyState from '$lib/components/ui/EmptyState.svelte';
  import { renderMathMarkdown, renderMathMarkdownInline } from '$lib/utils/mathMarkdown';
  import { get } from 'svelte/store';
  import { pendingReviewCards } from '$lib/stores/studySession';

  // sr_schedule.py 단일 source 미러 — '암'(correct) 다음 복습일 라벨 전용(실제 스케줄은 백엔드).
  // stage===null = 신규 카드(progress 없음): '암'이면 백엔드가 due 안 박음(외움→큐 제외)이라 '안 나옴'.
  const REVIEW_INTERVAL_DAYS = { 1: 3, 2: 7, 3: 14 };
  function correctLabel(stage) {
    if (stage === null || stage === undefined) return '안 나옴';
    const ns = stage + 1;
    if (ns >= 4) return '졸업';
    return `${REVIEW_INTERVAL_DAYS[ns]}일 뒤`;
  }

  let mode = $state('landing'); // 'landing' | 'review' | 'cram'
  let loading = $state(false);
  let busy = $state(false); // rate/view 진행 중 더블탭 방지
  let cards = $state([]);
  let idx = $state(0);
  let revealed = $state(false);
  let done = $state(false);
  let fmtFilter = $state(''); // '' | 'qa' | 'cloze' (cram)
  let tally = $state({ correct: 0, unsure: 0, wrong: 0 }); // 복습 결과 집계
  let seen = $state(0); // 그냥공부 본 카드 수
  let dueCount = $state(null); // landing 배지
  let marks = $state([]); // 카드별 결과 (데스크탑 좌측 진행트랙 점): 'correct'|'unsure'|'wrong'|'seen'|'flagged'

  function setMark(kind) {
    const m = [...marks];
    m[idx] = kind;
    marks = m;
  }
  // 데스크탑 진행트랙 점 클래스 (크기+색). 현재 카드는 accent 세로막대, 지난 카드는 결과색.
  function dotClass(i) {
    if (i === idx && !done) return 'h-4 w-1.5 bg-accent';
    const k = marks[i];
    if (k === 'correct') return 'h-1.5 w-1.5 bg-success';
    if (k === 'unsure') return 'h-1.5 w-1.5 bg-warning';
    if (k === 'wrong') return 'h-1.5 w-1.5 bg-error';
    if (k === 'seen' || k === 'flagged') return 'h-1.5 w-1.5 bg-faint';
    return 'h-1.5 w-1.5 bg-default';
  }

  let current = $derived(cards[idx] ?? null);
  let total = $derived(cards.length);
  let pct = $derived(total ? Math.round((idx / total) * 100) : 0);

  let _dueCache = null; // landing prefetch 한 due 카드 재사용

  async function fetchDue() {
    const d = (await api('/study-cards/due?limit=50')) ?? [];
    _dueCache = d;
    dueCount = d.length;
    return d;
  }

  async function startReview() {
    mode = 'review';
    loading = true;
    done = false;
    idx = 0;
    revealed = false;
    tally = { correct: 0, unsure: 0, wrong: 0 };
    marks = [];
    // 복습함(/study/review-box)에서 선택해 넘긴 카드가 있으면 그걸로 세션 구성.
    const preset = get(pendingReviewCards);
    if (preset && preset.length) {
      pendingReviewCards.set(null); // 소비
      cards = preset;
      loading = false;
      return;
    }
    try {
      cards = _dueCache ?? (await fetchDue());
      _dueCache = null; // 소비
    } catch (err) {
      addToast('error', err?.detail || '복습 카드 조회 실패');
      cards = [];
    } finally {
      loading = false;
    }
  }

  async function startCram() {
    mode = 'cram';
    loading = true;
    done = false;
    idx = 0;
    revealed = false;
    seen = 0;
    marks = [];
    try {
      const q = fmtFilter ? `?format=${fmtFilter}&limit=40` : '?limit=40';
      cards = (await api(`/study-cards/deck${q}`)) ?? [];
    } catch (err) {
      addToast('error', err?.detail || '학습 덱 조회 실패');
      cards = [];
    } finally {
      loading = false;
    }
  }

  function backToLanding() {
    mode = 'landing';
    cards = [];
    idx = 0;
    revealed = false;
    done = false;
    fetchDue().catch(() => { dueCount = null; });
  }

  function advance() {
    revealed = false;
    if (idx + 1 >= cards.length) done = true;
    else idx += 1;
  }

  async function rate(label) {
    if (!current || busy) return;
    busy = true;
    const c = current;
    try {
      await api(`/study-cards/${c.id}/rate`, {
        method: 'POST',
        body: JSON.stringify({ outcome: label }),
      });
      const key = label === '암' ? 'correct' : label === '애매' ? 'unsure' : 'wrong';
      tally = { ...tally, [key]: tally[key] + 1 };
      setMark(key);
      advance();
    } catch (err) {
      addToast('error', err?.detail || '평가 저장 실패');
    } finally {
      busy = false;
    }
  }

  async function markSeen() {
    if (!current || busy) return;
    busy = true;
    try {
      await api(`/study-cards/${current.id}/view`, { method: 'POST' });
      seen += 1;
      setMark('seen');
      advance();
    } catch (err) {
      addToast('error', err?.detail || '기록 실패');
    } finally {
      busy = false;
    }
  }

  // 학습 중 카드 내용이 이상하면 검수함(cards-review)으로 되돌림 (needs_review=true → 학습 큐에서 빠짐).
  let flagBusy = $state(false);
  async function flagCard() {
    if (!current || flagBusy || busy) return;
    flagBusy = true;
    const c = current;
    try {
      await api(`/study-cards/${c.id}`, { method: 'PATCH', body: JSON.stringify({ needs_review: true }) });
      addToast('success', '검수함으로 보냈어요 — 이 카드는 학습에서 빠집니다');
      setMark('flagged');
      advance();
    } catch (err) {
      addToast('error', err?.detail || '신고 처리 실패');
    } finally {
      flagBusy = false;
    }
  }

  function setCramFilter(f) {
    if (fmtFilter === f) return;
    fmtFilter = f;
    startCram();
  }

  // 카드 앞면 텍스트 (cloze=빈칸 문장 / qa=질문)
  function frontText(c) {
    if (c.format === 'cloze' && c.cloze_text) return c.cloze_text;
    return c.cue;
  }

  function onKey(e) {
    if (mode === 'landing' || loading || done || !current) return;
    if (e.key === ' ') {
      e.preventDefault();
      if (!revealed) revealed = true;
      return;
    }
    if (!revealed) return;
    if (mode === 'review') {
      if (e.key === 'j' || e.key === 'J') rate('모름');
      else if (e.key === 'k' || e.key === 'K') rate('애매');
      else if (e.key === 'l' || e.key === 'L') rate('암');
    } else if (mode === 'cram' && e.key === 'Enter') {
      markSeen();
    }
  }

  onMount(() => {
    window.addEventListener('keydown', onKey);
    const m = new URLSearchParams(window.location.search).get('mode');
    if (m === 'review') startReview();
    else if (m === 'cram') startCram();
    else fetchDue().catch(() => { dueCount = null; });
    return () => window.removeEventListener('keydown', onKey);
  });
</script>

<svelte:head><title>암기카드 학습</title></svelte:head>

<div class="mx-auto flex min-h-[100dvh] max-w-md flex-col px-4 py-4 sm:py-6 md:max-w-5xl md:px-6">
  <!-- 헤더 -->
  <div class="mb-4 flex items-center gap-2">
    {#if mode === 'landing'}
      <Button variant="ghost" size="sm" icon={ArrowLeft} onclick={() => goto('/study')}>공부</Button>
      <h1 class="text-lg font-bold text-text">암기카드 학습</h1>
    {:else}
      <Button variant="ghost" size="sm" icon={ArrowLeft} onclick={backToLanding}>나가기</Button>
      {#if !done && total > 0}
        <div class="h-1.5 flex-1 overflow-hidden rounded-full bg-default">
          <div class="h-full rounded-full bg-accent transition-all" style="width:{pct}%"></div>
        </div>
        <span class="shrink-0 text-xs tabular-nums text-dim">{Math.min(idx + 1, total)} / {total}</span>
      {:else}
        <h1 class="text-lg font-bold text-text">{mode === 'review' ? '복습' : '그냥 공부'}</h1>
      {/if}
    {/if}
  </div>

  {#if mode === 'cram' && !loading && !done}
    <!-- 그냥 공부 format 필터 (전환 시 덱 재시작) -->
    <div class="mb-3 flex gap-1.5">
      {#each [['', '전체'], ['cloze', 'cloze'], ['qa', 'qa']] as [val, label] (val)}
        <button
          class="rounded-full border px-2.5 py-1 text-xs font-semibold {fmtFilter === val ? 'border-accent bg-accent text-white' : 'border-default bg-surface text-dim'}"
          onclick={() => setCramFilter(val)}
        >{label}</button>
      {/each}
    </div>
  {/if}

  {#if mode === 'landing'}
    <!-- 트랙 선택 -->
    <p class="mb-4 text-sm text-dim md:mx-auto md:max-w-xl">검수 완료한 암기카드를 학습합니다. 두 가지 방법 중 선택하세요.</p>
    <div class="space-y-3 md:mx-auto md:max-w-xl">
      <button
        onclick={startReview}
        class="block w-full rounded-card border border-default bg-surface p-5 text-left transition-colors hover:border-accent hover:bg-accent/5"
      >
        <div class="mb-1.5 flex items-center gap-2">
          <Repeat size={18} class="text-accent" />
          <h2 class="text-base font-semibold text-text">복습 (간격반복)</h2>
          {#if dueCount !== null && dueCount > 0}
            <span class="ml-auto rounded-full bg-accent px-2 py-0.5 text-xs font-bold text-white">오늘 {dueCount}장</span>
          {/if}
        </div>
        <p class="text-xs text-dim">
          오늘 복습할 카드를 앞면만 보고 떠올린 뒤 <b class="text-text">모름·애매·암</b>으로 자기평가합니다.
          암이면 복습 간격이 늘고(1·3·7·14일), 애매·모름은 내일 다시 나옵니다.
        </p>
      </button>

      <button
        onclick={startCram}
        class="block w-full rounded-card border border-default bg-surface p-5 text-left transition-colors hover:border-accent hover:bg-accent/5"
      >
        <div class="mb-1.5 flex items-center gap-2">
          <Layers size={18} class="text-accent" />
          <h2 class="text-base font-semibold text-text">그냥 공부</h2>
        </div>
        <p class="text-xs text-dim">
          아직 덜 본 카드부터 가볍게 넘겨보며 <b class="text-text">봤어요</b>만 기록해요. 복습 일정과는 무관해요.
        </p>
      </button>
    </div>

  {:else if loading}
    <div class="flex-1 space-y-3"><Skeleton class="h-64 w-full" /><Skeleton class="h-12 w-full" /></div>

  {:else if done}
    <!-- 결과 화면 -->
    <div class="flex flex-1 flex-col items-center justify-center text-center">
      {#if mode === 'review'}
        <div class="text-lg font-bold text-text">오늘 복습을 마쳤어요</div>
        <div class="my-6 flex gap-9">
          <div><div class="text-3xl font-extrabold text-success">{tally.correct}</div><div class="text-xs text-dim">암</div></div>
          <div><div class="text-3xl font-extrabold text-warning">{tally.unsure}</div><div class="text-xs text-dim">애매</div></div>
          <div><div class="text-3xl font-extrabold text-error">{tally.wrong}</div><div class="text-xs text-dim">모름</div></div>
        </div>
        <p class="text-xs text-dim">애매하거나 몰랐던 카드는 내일 다시 만나요. 외운 카드는 간격만큼 쉬어요.</p>
      {:else}
        <div class="text-lg font-bold text-text">훑어보기 완료</div>
        <div class="my-6 text-3xl font-extrabold text-accent">{seen}<span class="ml-1 text-sm font-medium text-dim">장</span></div>
        <p class="text-xs text-dim">'봤어요'로 표시한 카드는 다음엔 덜 본 순서 뒤로 가요.</p>
      {/if}
      <div class="mt-7 flex gap-2">
        <Button variant="secondary" onclick={backToLanding}>다시 고르기</Button>
        <Button variant="primary" onclick={() => goto('/study')}>공부로 돌아가기</Button>
      </div>
    </div>

  {:else if total === 0}
    <!-- 빈 큐 -->
    <div class="flex flex-1 items-center justify-center">
      {#if mode === 'review'}
        <EmptyState
          title="오늘 복습할 카드가 없습니다"
          description="자기평가에서 애매·모름으로 표시한 카드가 복습일이 되면 여기에 나타납니다. '그냥 공부'로 가볍게 훑어볼 수 있어요."
          icon={Repeat}
        />
      {:else}
        <EmptyState
          title="학습할 카드가 없습니다"
          description="문제를 풀면 AI가 암기카드를 추출하고, 검수를 마친 카드가 여기에 쌓입니다."
          icon={BookOpen}
        />
      {/if}
    </div>

  {:else if current}
    <!-- 카드 — 모바일: 단일 카드 / 데스크탑(md+): Focus Stage(좌 진행트랙·중앙 무대카드·우 근거) -->
    <div class="flex flex-1 flex-col md:grid md:grid-cols-[170px_minmax(0,1fr)_260px] md:items-center md:gap-6">
      <!-- 좌측 진행 트랙 (데스크탑 전용) -->
      <div class="hidden md:flex md:flex-col md:items-center md:justify-center md:self-stretch md:py-4">
        <div class="text-xs font-bold tabular-nums text-dim">{Math.min(idx + 1, total)} / {total}</div>
        <div class="my-4 flex max-h-[280px] flex-col items-center gap-1 overflow-y-auto">
          {#each cards as _, i (i)}
            <span class="shrink-0 rounded-full transition-all {dotClass(i)}"></span>
          {/each}
        </div>
        {#if mode === 'review'}
          <div class="text-center text-[11px] leading-relaxed text-dim">암 <b class="text-success">{tally.correct}</b> · 애매 <b class="text-warning">{tally.unsure}</b> · 모름 <b class="text-error">{tally.wrong}</b></div>
        {:else}
          <div class="text-center text-[11px] text-dim">본 카드 <b class="text-accent">{seen}</b></div>
        {/if}
      </div>

      <!-- 중앙 무대 카드 + 평가 -->
      <div class="flex flex-1 flex-col md:block md:w-full md:max-w-[600px] md:justify-self-center">
        <div class="flex flex-1 flex-col rounded-card border border-default bg-surface p-5 md:flex-none md:min-h-[360px] md:p-8 md:shadow-md">
          <div class="flex items-center justify-between gap-2">
            <span
              class="rounded-full px-2.5 py-0.5 text-[10px] font-bold text-white {current.format === 'cloze' ? 'bg-accent' : 'bg-domain-engineering'}"
            >{current.format}</span>
            <button
              type="button"
              onclick={flagCard}
              disabled={flagBusy || busy}
              class="flex items-center gap-1 rounded-full border border-default px-2.5 py-1 text-[11px] font-medium text-dim transition-colors hover:border-warning hover:bg-warning/10 hover:text-warning disabled:opacity-50"
              title="카드 내용이 이상하면 검수함으로 보냅니다"
            >
              <Flag size={12} /> 이 카드 이상해요
            </button>
          </div>

          <div class="mt-3 text-[10px] font-bold uppercase tracking-wide text-faint">
            앞 — {current.format === 'qa' ? '질문' : '떠올리기'}
          </div>
          <div class="math-area mt-1 break-words text-lg font-semibold leading-relaxed text-text md:mt-2 md:text-2xl">{@html renderMathMarkdownInline(frontText(current))}</div>

          {#if revealed}
            <div class="mt-4 rounded-lg border border-accent-ring bg-bg px-4 py-3 md:mt-6">
              <div class="text-[10px] font-bold uppercase tracking-wide text-faint">정답</div>
              <div class="math-area mt-0.5 break-words text-xl font-bold text-accent md:text-3xl">{@html renderMathMarkdownInline(current.fact)}</div>
              {#if current.evidence?.length && current.evidence[0].snippet}
                <div class="mt-2 md:hidden">
                  <div class="text-[10px] font-bold uppercase tracking-wide text-faint">근거</div>
                  <div class="markdown-body math-area mt-1 overflow-x-auto text-xs leading-relaxed text-dim">{@html renderMathMarkdown(current.evidence[0].snippet)}</div>
                </div>
              {/if}
            </div>
          {/if}

          {#if !revealed}
            <button
              onclick={() => (revealed = true)}
              class="mt-auto flex items-center justify-center gap-2 rounded-md border border-dashed border-accent-ring bg-surface-hover py-3 text-sm font-medium text-accent transition-colors hover:bg-accent/5"
            >
              <Eye size={16} /> 탭하면 정답이 보여요 <span class="hidden text-faint sm:inline">· Space</span>
            </button>
          {/if}
        </div>

        <!-- 평가/액션 (reveal 후) -->
        {#if revealed}
          {#if mode === 'review'}
            <div class="mt-3 grid grid-cols-3 gap-2">
              <button
                onclick={() => rate('모름')}
                disabled={busy}
                class="flex flex-col items-center rounded-lg bg-error py-3.5 text-sm font-bold text-white transition-opacity hover:opacity-90 disabled:opacity-50"
              >모름<span class="mt-0.5 text-[10px] font-medium opacity-85">내일 다시</span></button>
              <button
                onclick={() => rate('애매')}
                disabled={busy}
                class="flex flex-col items-center rounded-lg bg-warning py-3.5 text-sm font-bold text-white transition-opacity hover:opacity-90 disabled:opacity-50"
              >애매<span class="mt-0.5 text-[10px] font-medium opacity-85">내일 다시</span></button>
              <button
                onclick={() => rate('암')}
                disabled={busy}
                class="flex flex-col items-center rounded-lg bg-success py-3.5 text-sm font-bold text-white transition-opacity hover:opacity-90 disabled:opacity-50"
              >암<span class="mt-0.5 text-[10px] font-medium opacity-85">{correctLabel(current.review_stage)}</span></button>
            </div>
            <p class="mt-2 hidden text-center text-[11px] text-faint sm:block">키보드: Space 정답 · J 모름 · K 애매 · L 암</p>
          {:else}
            <button
              onclick={markSeen}
              disabled={busy}
              class="mt-3 w-full rounded-lg bg-accent py-3.5 text-sm font-bold text-white transition-colors hover:bg-accent-hover disabled:opacity-50"
            >봤어요 · 다음 <span class="hidden text-xs font-medium opacity-85 sm:inline">Enter</span></button>
          {/if}
        {/if}
      </div>

      <!-- 우측 근거 (데스크탑 전용; reveal 시 채움, 자리 예약으로 레이아웃 점프 0) -->
      <div class="hidden md:flex md:flex-col md:self-stretch md:justify-center">
        {#if revealed && current.evidence?.length && current.evidence[0].snippet}
          <div class="max-h-[70vh] overflow-y-auto rounded-lg border border-default bg-surface p-4">
            <div class="text-[10px] font-bold uppercase tracking-wide text-faint">근거</div>
            <div class="markdown-body math-area mt-1.5 overflow-x-auto text-xs leading-relaxed text-dim">{@html renderMathMarkdown(current.evidence[0].snippet)}</div>
          </div>
        {:else if revealed}
          <div class="rounded-lg border border-dashed border-default p-4 text-[11px] leading-relaxed text-faint">확정 풀이에서 추출한 카드 — 별도 인용 없음</div>
        {/if}
      </div>
    </div>
  {/if}
</div>
