<script>
  /**
   * /study/topics/[id]/review-queue — 복습함 (Phase 2-C).
   *
   * 5 탭 (오늘 할 일 / 미확인 / 반복 오답 / 퇴행 / 학습완료) + paginated 카드.
   * backend GET /study-topics/{tid}/review-queue?tab=...&page=..&page_size=..
   * 카드 클릭 → 개별 문제 페이지. 멀티 셀렉트 풀이 (세션 만들기) 는 후속.
   */
  import { onMount } from 'svelte';
  import { page } from '$app/stores';
  import { goto } from '$app/navigation';
  import { api } from '$lib/api';
  import { addToast } from '$lib/stores/toast';
  import {
    ArrowLeft, AlertCircle, Clock, RotateCcw, Repeat2, CheckCircle2, ChevronLeft, ChevronRight,
    Play, Square, CheckSquare,
  } from 'lucide-svelte';
  import Button from '$lib/components/ui/Button.svelte';
  import Card from '$lib/components/ui/Card.svelte';
  import Skeleton from '$lib/components/ui/Skeleton.svelte';
  import EmptyState from '$lib/components/ui/EmptyState.svelte';

  const MAX_PER_SESSION = 200;

  const TABS = [
    { key: 'due_today',      label: '오늘 할 일',  icon: Clock,        accent: 'text-warning' },
    { key: 'pending_review', label: '미확인',      icon: AlertCircle,  accent: 'text-error' },
    { key: 'chronic',        label: '반복 오답',   icon: Repeat2,      accent: 'text-warning' },
    { key: 'regressed',      label: '퇴행',        icon: RotateCcw,    accent: 'text-error' },
    { key: 'mastered',       label: '학습완료',    icon: CheckCircle2, accent: 'text-success' },
  ];
  const PAGE_SIZE = 50;

  let topicId = $derived(Number($page.params.id));
  let topicName = $state('');

  // ?tab= URL 동기. 새로고침 / 뒤로가기 보존.
  let activeTab = $state('due_today');
  let currentPage = $state(1);
  let total = $state(0);
  let items = $state([]);
  let loading = $state(false);
  let counts = $state({}); // { tab: total }
  let overdueCount = $state(0);

  // 멀티 셀렉트 (현재 페이지 보이는 카드 기준 선택. 페이지 이동 시 유지).
  let selected = $state(new Set()); // Set<number> — question_id
  let starting = $state(false);
  let redistributing = $state(false);

  async function loadTopic() {
    try {
      const t = await api(`/study-topics/${topicId}`);
      topicName = t?.topic?.name ?? '';
    } catch {}
  }

  async function loadCounts() {
    // 5탭 카운트만 빠르게 (page_size=1). backend 변경 0.
    const promises = TABS.map(async (t) => {
      try {
        const r = await api(`/study-topics/${topicId}/review-queue?tab=${t.key}&page=1&page_size=1`);
        return [t.key, r?.total ?? 0];
      } catch {
        return [t.key, 0];
      }
    });
    const pairs = await Promise.all(promises);
    counts = Object.fromEntries(pairs);
  }

  async function loadTab() {
    loading = true;
    try {
      const r = await api(
        `/study-topics/${topicId}/review-queue?tab=${activeTab}&page=${currentPage}&page_size=${PAGE_SIZE}`,
      );
      total = r?.total ?? 0;
      items = r?.items ?? [];
      overdueCount = r?.overdue_count ?? 0;
    } catch (err) {
      addToast('error', err?.detail || '복습함 조회 실패');
      total = 0;
      items = [];
      overdueCount = 0;
    } finally {
      loading = false;
    }
  }

  async function redistributeOverdue() {
    if (overdueCount === 0 || redistributing) return;
    if (!confirm(
      `정체된 복습 ${overdueCount}건을 1~7일에 걸쳐 균등 분산합니다. 학습 단계는 그대로 유지됩니다. 진행할까요?`,
    )) return;
    redistributing = true;
    try {
      const res = await api(`/study-topics/${topicId}/review-queue/redistribute`, {
        method: 'POST',
        body: JSON.stringify({ spread_days: 7 }),
      });
      addToast('success', `${res.redistributed_count}건을 ${res.spread_days}일에 분산했습니다`);
      // 카운트 + 목록 새로고침
      await Promise.all([loadCounts(), loadTab()]);
    } catch (err) {
      addToast('error', err?.detail || '정리 실패');
    } finally {
      redistributing = false;
    }
  }

  function setTab(key) {
    if (activeTab === key) return;
    activeTab = key;
    currentPage = 1;
    selected = new Set();  // 탭 바뀌면 선택 초기화 — 다른 의도의 묶음일 가능성
    // URL 동기 — replaceState 로 history 폭발 방지
    const url = new URL($page.url);
    url.searchParams.set('tab', key);
    url.searchParams.delete('page');
    history.replaceState(null, '', url.toString());
    void loadTab();
  }

  function toggleSelect(qid) {
    const next = new Set(selected);
    if (next.has(qid)) next.delete(qid);
    else {
      if (next.size >= MAX_PER_SESSION) {
        addToast('warning', `한 세션에 최대 ${MAX_PER_SESSION}문제까지 선택 가능합니다`);
        return;
      }
      next.add(qid);
    }
    selected = next;
  }

  function toggleSelectVisible() {
    const visibleIds = items.map((it) => it.question_id);
    const allSelected = visibleIds.length > 0 && visibleIds.every((id) => selected.has(id));
    const next = new Set(selected);
    if (allSelected) {
      visibleIds.forEach((id) => next.delete(id));
    } else {
      for (const id of visibleIds) {
        if (next.size >= MAX_PER_SESSION) break;
        next.add(id);
      }
    }
    selected = next;
  }

  function clearSelection() {
    selected = new Set();
  }

  /** 선택된 N개로 quiz_session 시작. 기존 in_progress 있으면 confirm 후 abandon. */
  async function startSelectedSession() {
    if (selected.size === 0) return;
    if (starting) return;
    // 기존 in_progress 가 있는지 확인 — 토픽 페이지의 startNewQuiz 패턴 참고
    let hasActive = false;
    try {
      const sessions = await api(`/study-topics/${topicId}/quiz-sessions?limit=1`);
      hasActive = !!sessions?.active;
    } catch {}
    if (hasActive) {
      if (!confirm(
        `진행 중인 문제풀이 세션이 있습니다. 새로 시작하면 그 세션은 포기됩니다. 계속할까요?`,
      )) return;
    }
    starting = true;
    try {
      const qids = Array.from(selected);
      const res = await api(`/study-topics/${topicId}/quiz-sessions`, {
        method: 'POST',
        body: JSON.stringify({
          question_ids: qids,
          quiz_mode: 'random',
          abandon_existing: hasActive,
        }),
      });
      goto(`/study/topics/${topicId}/review?session=${res.id}`);
    } catch (err) {
      addToast('error', err?.detail || '풀이 시작 실패');
      starting = false;
    }
  }

  function setPage(p) {
    if (p < 1 || (p - 1) * PAGE_SIZE >= total) return;
    currentPage = p;
    const url = new URL($page.url);
    if (p === 1) url.searchParams.delete('page');
    else url.searchParams.set('page', String(p));
    history.replaceState(null, '', url.toString());
    void loadTab();
  }

  onMount(async () => {
    // URL 에서 초기 탭 / 페이지 복원
    const tabParam = $page.url.searchParams.get('tab');
    const pageParam = Number($page.url.searchParams.get('page') || 1);
    if (tabParam && TABS.some((t) => t.key === tabParam)) activeTab = tabParam;
    if (pageParam >= 1) currentPage = pageParam;
    await loadTopic();
    await Promise.all([loadCounts(), loadTab()]);
  });

  // 패턴/상태 → 한국어 라벨
  function patternLabel(state) {
    return ({
      stable: '안정',
      unstable: '불안정',
      unsure: '모르겠음',
      regressed: '퇴행',
      recovered: '회복',
      chronic_wrong: '반복 오답',
      unattempted: '미학습',
    }[state] ?? state ?? '');
  }
  function outcomeBadge(o) {
    if (o === 'correct') return { text: '정답', cls: 'text-success bg-success/10' };
    if (o === 'wrong')   return { text: '오답', cls: 'text-error bg-error/10' };
    if (o === 'unsure')  return { text: '모르겠음', cls: 'text-warning bg-warning/10' };
    if (o === 'skipped') return { text: '스킵', cls: 'text-dim bg-bg/30' };
    return null;
  }

  function fmtRelative(d) {
    if (!d) return '';
    const t = new Date(d).getTime();
    const now = Date.now();
    const diff = t - now;
    const abs = Math.abs(diff);
    const day = 86400000;
    const hour = 3600000;
    if (abs < hour) return diff > 0 ? '곧' : '방금';
    if (abs < day) {
      const h = Math.round(abs / hour);
      return diff > 0 ? `${h}시간 후` : `${h}시간 전`;
    }
    const d2 = Math.round(abs / day);
    return diff > 0 ? `${d2}일 후` : `${d2}일 전`;
  }
  function fmtDate(d) {
    if (!d) return '';
    return new Date(d).toLocaleDateString('ko-KR', { month: 'short', day: 'numeric' });
  }

  let lastPage = $derived(Math.max(1, Math.ceil(total / PAGE_SIZE)));
  let allVisibleSelected = $derived(
    items.length > 0 && items.every((it) => selected.has(it.question_id))
  );
</script>

<svelte:head><title>복습함 — {topicName || '주제'}</title></svelte:head>

<div class="p-4 md:p-6 max-w-3xl mx-auto">
  <div class="flex items-center gap-2 text-xs md:text-sm mb-3">
    <a href="/study" class="text-dim hover:text-text">공부</a>
    <span class="text-faint">/</span>
    <a href="/study/topics" class="text-dim hover:text-text">주제</a>
    <span class="text-faint">/</span>
    <a href={`/study/topics/${topicId}`} class="text-dim hover:text-text truncate">{topicName || '...'}</a>
    <span class="text-faint">/</span>
    <span class="text-text font-medium">복습함</span>
  </div>

  <Card>
    {#snippet children()}
      <div class="p-5 flex flex-col gap-4">
        <h1 class="text-base font-semibold text-text">복습함</h1>

        <!-- Phase 2-F: due_today 탭에서만 정체 경고 + 정리 버튼 -->
        {#if activeTab === 'due_today' && overdueCount > 0}
          <div class="rounded border border-warning/40 bg-warning/5 p-3 text-xs text-text flex items-center gap-3 flex-wrap">
            <AlertCircle size={14} class="text-warning shrink-0" />
            <div class="flex-1 min-w-0">
              <div>오늘 할 일 중 <span class="text-warning font-medium">{overdueCount}건</span>이 어제 이전부터 정체된 복습입니다.</div>
              <div class="text-dim mt-0.5">1~7일에 균등 분산해서 페이스를 회복할 수 있습니다.</div>
            </div>
            <Button size="sm" variant="ghost" loading={redistributing} onclick={redistributeOverdue}>정리</Button>
          </div>
        {/if}

        <!-- 탭 -->
        <div class="flex flex-wrap gap-1 border-b border-default">
          {#each TABS as t}
            {@const Icon = t.icon}
            {@const cnt = counts[t.key] ?? 0}
            {@const active = activeTab === t.key}
            <button
              type="button"
              onclick={() => setTab(t.key)}
              class="px-3 py-2 text-xs md:text-sm border-b-2 transition-colors flex items-center gap-1.5
                {active ? `border-current font-medium ${t.accent}` : 'border-transparent text-dim hover:text-text'}"
            >
              <Icon size={14} />
              <span>{t.label}</span>
              <span class="text-[10px] bg-bg/40 text-dim rounded px-1.5 py-0.5">{cnt}</span>
            </button>
          {/each}
        </div>

        {#if loading}
          <Skeleton h="h-32" rounded="lg" />
        {:else if items.length === 0}
          <EmptyState
            title="이 탭에 표시할 문제가 없습니다"
            description={
              activeTab === 'due_today' ? '오늘 풀어야 할 복습이 없습니다. 새로 풀이를 시작해보세요.'
              : activeTab === 'pending_review' ? '미확인 오답·모르겠음 이 없습니다. 결과 화면에서 학습완료를 표시하면 여기서 사라집니다.'
              : activeTab === 'chronic' ? '최근 3회 중 오답이 2회 이상인 문제가 없습니다.'
              : activeTab === 'regressed' ? '맞혔다가 다시 틀린 문제가 없습니다.'
              : '학습완료 (4단계 통과) 한 문제가 아직 없습니다.'
            }
          />
        {:else}
          <!-- 일괄 선택 동선 — 페이지 단위 -->
          <div class="flex items-center gap-2 text-xs">
            <button
              type="button"
              onclick={toggleSelectVisible}
              class="flex items-center gap-1.5 text-dim hover:text-text"
            >
              {#if allVisibleSelected}<CheckSquare size={14} />{:else}<Square size={14} />{/if}
              <span>이 페이지 {allVisibleSelected ? '선택 해제' : '전체 선택'} ({items.length})</span>
            </button>
            {#if selected.size > 0}
              <span class="text-dim">·</span>
              <button type="button" onclick={clearSelection} class="text-dim hover:text-text">선택 모두 해제</button>
            {/if}
          </div>

          <ul class="flex flex-col gap-2">
            {#each items as it (it.question_id)}
              {@const ob = outcomeBadge(it.last_outcome)}
              {@const checked = selected.has(it.question_id)}
              <li class="rounded border bg-surface flex items-stretch
                {checked ? 'border-accent/60 bg-accent/5' : 'border-default'}">
                <button
                  type="button"
                  onclick={() => toggleSelect(it.question_id)}
                  aria-label={checked ? '선택 해제' : '선택'}
                  class="px-3 flex items-center hover:bg-bg/30 transition-colors border-r border-default"
                >
                  {#if checked}<CheckSquare size={16} class="text-accent" />{:else}<Square size={16} class="text-dim" />{/if}
                </button>
                <a
                  href={`/study/topics/${topicId}/questions/${it.question_id}`}
                  class="flex-1 min-w-0 p-3 hover:bg-bg/30 transition-colors"
                >
                  <div class="text-sm text-text line-clamp-2">{it.question_text}</div>
                  <div class="text-[11px] text-dim mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-0.5">
                    {#if it.subject}<span>{it.subject}</span>{/if}
                    {#if it.scope}<span>· {it.scope}</span>{/if}
                    {#if it.exam_round}<span>· {it.exam_round}</span>{/if}
                    {#if ob}<span class="rounded px-1.5 py-0.5 {ob.cls}">{ob.text}</span>{/if}
                    {#if it.pattern_state}
                      <span class="text-dim">패턴: {patternLabel(it.pattern_state)}</span>
                    {/if}
                    {#if it.due_at}
                      <span class="text-warning">복습 {fmtRelative(it.due_at)}</span>
                    {/if}
                    {#if (it.review_stage ?? 0) >= 1}
                      <span class="text-success">stage {it.review_stage}</span>
                    {/if}
                    {#if it.last_attempted_at}
                      <span class="ml-auto text-faint">최근 {fmtDate(it.last_attempted_at)}</span>
                    {/if}
                  </div>
                </a>
              </li>
            {/each}
          </ul>

          <!-- 페이지네이션 -->
          {#if lastPage > 1}
            <div class="flex items-center justify-between text-xs text-dim pt-2 border-t border-default">
              <span>총 {total}건 · {currentPage} / {lastPage} 페이지</span>
              <div class="flex gap-1">
                <Button size="sm" variant="ghost" disabled={currentPage <= 1} onclick={() => setPage(currentPage - 1)} icon={ChevronLeft}>이전</Button>
                <Button size="sm" variant="ghost" disabled={currentPage >= lastPage} onclick={() => setPage(currentPage + 1)} icon={ChevronRight}>다음</Button>
              </div>
            </div>
          {/if}
        {/if}

        <div class="flex justify-end pt-2 border-t border-default">
          <Button href={`/study/topics/${topicId}`} variant="ghost" icon={ArrowLeft}>주제로</Button>
        </div>
      </div>
    {/snippet}
  </Card>
</div>

<!-- Phase 2-E: 선택 N개 풀이 시작 sticky bar -->
{#if selected.size > 0}
  <div class="fixed bottom-0 inset-x-0 z-30 border-t border-accent/40 bg-surface/95 backdrop-blur p-3 flex items-center gap-3 max-w-3xl mx-auto sm:rounded-t-lg sm:bottom-2 sm:border sm:left-2 sm:right-2">
    <span class="text-sm text-text">
      <span class="font-semibold text-accent">{selected.size}</span> 개 선택됨
      {#if selected.size >= MAX_PER_SESSION}
        <span class="text-xs text-warning ml-1">(최대)</span>
      {/if}
    </span>
    <button type="button" onclick={clearSelection} class="text-xs text-dim hover:text-text">해제</button>
    <Button class="ml-auto" size="sm" icon={Play} loading={starting} onclick={startSelectedSession}>
      {selected.size}개 풀이 시작
    </Button>
  </div>
{/if}
