<script>
  // Phase F — Inbox 분류 UX 전면 재작성.
  // - F.1: review_status: 'approved' PATCH body 누락 버그 수정 + 미분류 가드
  // - F.2: runes mode + ui/* 프리미티브
  // - F.3: source/format 필터 row (confidence는 백엔드 대기)
  // - F.4: 처리 단계 타임스탬프 Badge 3개 (stop-gap)
  // - F.5: 행별 도메인 override + tag 인라인 (로컬 state, 승인 시 반영)
  // - F.6: 배치 override modal + (재시도 stub는 queue retry 백엔드 대기)
  import { onMount } from 'svelte';
  import { api } from '$lib/api';
  import { addToast } from '$lib/stores/toast';
  import { ui } from '$lib/stores/uiState.svelte';
  import { pLimit } from '$lib/utils/pLimit';
  import { AlertTriangle, CheckCircle2, RotateCcw, Inbox as InboxIcon } from 'lucide-svelte';
  import Card from '$lib/components/ui/Card.svelte';
  import Button from '$lib/components/ui/Button.svelte';
  import Select from '$lib/components/ui/Select.svelte';
  import TextInput from '$lib/components/ui/TextInput.svelte';
  import Badge from '$lib/components/ui/Badge.svelte';
  import EmptyState from '$lib/components/ui/EmptyState.svelte';
  import Skeleton from '$lib/components/ui/Skeleton.svelte';
  import Modal from '$lib/components/ui/Modal.svelte';
  import ConfirmDialog from '$lib/components/ui/ConfirmDialog.svelte';
  import FormatIcon from '$lib/components/FormatIcon.svelte';
  import TagPill from '$lib/components/TagPill.svelte';

  const DOMAIN_OPTIONS = [
    { value: 'Knowledge/Philosophy', label: 'Knowledge / Philosophy' },
    { value: 'Knowledge/Language', label: 'Knowledge / Language' },
    { value: 'Knowledge/Engineering', label: 'Knowledge / Engineering' },
    { value: 'Knowledge/Industrial_Safety', label: 'Knowledge / Industrial Safety' },
    { value: 'Knowledge/Programming', label: 'Knowledge / Programming' },
    { value: 'Knowledge/General', label: 'Knowledge / General' },
    { value: 'Reference', label: 'Reference' },
  ];

  const MAX_SELECTION = 50;

  let documents = $state([]);
  let loading = $state(true);
  let busy = $state(false);

  // 선택
  let selected = $state(new Set());

  // F.3 필터
  let filterSource = $state('');
  let filterFormat = $state('');

  // F.5 행별 override Map<id, { domain?, tags? }>
  let overrides = $state(new Map());

  // F.6 batch override 입력
  let batchDomainValue = $state('');
  let batchTagValue = $state('');

  onMount(loadInbox);

  async function loadInbox() {
    loading = true;
    try {
      // 서버 필터 review_status=pending 적용 — page_size 100 이내 안전
      const data = await api('/documents/?review_status=pending&page_size=100');
      documents = data.items || [];
    } catch (err) {
      addToast('error', 'Inbox 로딩 실패');
    } finally {
      loading = false;
    }
  }

  // Derived
  let filteredDocs = $derived(
    documents.filter((d) => {
      if (filterSource && d.source_channel !== filterSource) return false;
      if (filterFormat && d.file_format !== filterFormat) return false;
      return true;
    })
  );

  let sourceOptions = $derived.by(() => {
    const set = new Set(documents.map((d) => d.source_channel).filter(Boolean));
    return [
      { value: '', label: '모든 소스' },
      ...[...set].map((s) => ({ value: s, label: s })),
    ];
  });

  let formatOptions = $derived.by(() => {
    const set = new Set(documents.map((d) => d.file_format).filter(Boolean));
    return [
      { value: '', label: '모든 형식' },
      ...[...set].map((f) => ({ value: f, label: f.toUpperCase() })),
    ];
  });

  // Helper: override 고려한 effective domain/tags
  function effectiveDomain(doc) {
    const ov = overrides.get(doc.id);
    if (ov && ov.domain !== undefined) return ov.domain;
    return doc.ai_domain ?? '';
  }

  function effectiveTags(doc) {
    const ov = overrides.get(doc.id);
    if (ov && ov.tags !== undefined) return ov.tags;
    return doc.ai_tags ?? [];
  }

  function isApprovable(doc) {
    return !!effectiveDomain(doc);
  }

  // F.5 override setter
  function setDomainOverride(id, value) {
    const next = new Map(overrides);
    const existing = next.get(id) ?? {};
    next.set(id, { ...existing, domain: value });
    overrides = next;
  }

  function clearOverride(id) {
    const next = new Map(overrides);
    next.delete(id);
    overrides = next;
    // 미분류로 돌아가면 선택에서도 제거
    const doc = documents.find((d) => d.id === id);
    if (doc && !isApprovable(doc) && selected.has(id)) {
      const nextSel = new Set(selected);
      nextSel.delete(id);
      selected = nextSel;
    }
  }

  // Selection
  function toggleSelect(id) {
    const doc = documents.find((d) => d.id === id);
    if (!doc || !isApprovable(doc)) return;
    const next = new Set(selected);
    if (next.has(id)) next.delete(id);
    else next.add(id);
    selected = next;
  }

  function toggleAll() {
    const approvable = filteredDocs.filter(isApprovable);
    const allSelected = approvable.length > 0 && approvable.every((d) => selected.has(d.id));
    if (allSelected) {
      selected = new Set();
    } else {
      selected = new Set(approvable.map((d) => d.id));
    }
  }

  let selectionCount = $derived(selected.size);
  let selectionOverLimit = $derived(selectionCount > MAX_SELECTION);
  let approvableCount = $derived(filteredDocs.filter(isApprovable).length);
  let unclassifiedCount = $derived(documents.filter((d) => !isApprovable(d)).length);

  // F.1 fix + 일괄 승인 (pLimit 5)
  async function confirmApprove() {
    const ids = [...selected];
    if (ids.length === 0 || ids.length > MAX_SELECTION) return;
    busy = true;
    const limit = pLimit(5);
    const results = await Promise.allSettled(
      ids.map((id) => limit(() => approveOne(id)))
    );
    busy = false;
    const success = results.filter((r) => r.status === 'fulfilled').length;
    const failed = results.length - success;
    if (success > 0) addToast('success', `${success}건 승인 완료`);
    if (failed > 0) addToast('error', `${failed}건 실패`);
    selected = new Set();
    overrides = new Map();
    loadInbox();
  }

  async function approveOne(id) {
    const doc = documents.find((d) => d.id === id);
    if (!doc) return;
    const ov = overrides.get(id) ?? {};
    const body = {
      review_status: 'approved', // F.1: 누락 버그 수정 (핵심)
      ai_domain: ov.domain ?? doc.ai_domain,
    };
    if (ov.tags !== undefined) body.ai_tags = ov.tags;
    return api(`/documents/${id}`, {
      method: 'PATCH',
      body: JSON.stringify(body),
    });
  }

  // F.6 배치 override — 로컬 상태만 변경, 실제 PATCH는 승인 시점에
  function applyBatchDomain() {
    if (!batchDomainValue) return;
    const next = new Map(overrides);
    for (const id of selected) {
      const existing = next.get(id) ?? {};
      next.set(id, { ...existing, domain: batchDomainValue });
    }
    overrides = next;
    addToast('success', `${selected.size}건에 도메인 override`);
    batchDomainValue = '';
    ui.closeModal('batch-override-domain');
  }

  function applyBatchTag() {
    const tag = batchTagValue.trim();
    if (!tag) return;
    const next = new Map(overrides);
    for (const id of selected) {
      const doc = documents.find((d) => d.id === id);
      const existing = next.get(id) ?? {};
      const current = existing.tags ?? doc?.ai_tags ?? [];
      if (!current.includes(tag)) {
        next.set(id, { ...existing, tags: [...current, tag] });
      }
    }
    overrides = next;
    addToast('success', `${selected.size}건에 태그 추가`);
    batchTagValue = '';
    ui.closeModal('batch-override-tag');
  }

  // F.6 재시도 stub — 백엔드 POST /queue/retry 대기
  function retryStub() {
    addToast('warning', '재시도 엔드포인트 구현 대기 중 (TODO backend)');
  }
</script>

<div class="p-4 lg:p-6 max-w-5xl mx-auto">
  <!-- 헤더 -->
  <div class="flex items-center justify-between mb-4">
    <div class="flex items-center gap-3">
      <h2 class="text-lg font-semibold text-text">Inbox</h2>
      <Badge tone="warning" size="sm">{documents.length}</Badge>
      {#if unclassifiedCount > 0}
        <Badge tone="warning" size="sm">
          <AlertTriangle size={10} />
          미분류 {unclassifiedCount}
        </Badge>
      {/if}
    </div>
    <div class="flex items-center gap-2">
      <Button
        variant="ghost"
        size="sm"
        onclick={toggleAll}
        disabled={approvableCount === 0}
      >
        {selected.size === approvableCount && approvableCount > 0 ? '전체 해제' : '전체 선택'}
      </Button>
      <Button
        variant="secondary"
        size="sm"
        icon={RotateCcw}
        onclick={retryStub}
        disabled
        title="백엔드 구현 대기"
      >
        재시도
      </Button>
      <Button
        variant="primary"
        size="sm"
        onclick={() => ui.openModal('approve-confirm')}
        disabled={busy || selectionCount === 0 || selectionOverLimit}
        loading={busy}
      >
        선택 승인 ({selectionCount})
      </Button>
    </div>
  </div>

  <!-- F.3 필터 row -->
  <div class="flex flex-wrap items-center gap-2 mb-4">
    <div class="w-44">
      <Select bind:value={filterSource} options={sourceOptions} />
    </div>
    <div class="w-36">
      <Select bind:value={filterFormat} options={formatOptions} />
    </div>
    <!-- confidence: TODO(backend) — ai_confidence 필드 추가 시 복원 -->
  </div>

  <!-- F.6 선택 toolbar (batch override) -->
  {#if selectionCount > 0}
    <div
      class="sticky top-0 z-dropdown flex flex-wrap items-center gap-2 px-3 py-2 mb-4 rounded-md bg-accent/10 border border-accent/30 backdrop-blur-sm"
    >
      <span class="text-xs font-medium {selectionOverLimit ? 'text-error' : 'text-accent'}">
        {selectionCount}건 선택
        {#if selectionOverLimit}
          <span class="ml-1">(최대 {MAX_SELECTION}건 초과)</span>
        {/if}
      </span>
      <div class="flex-1"></div>
      <Button
        variant="secondary"
        size="sm"
        onclick={() => ui.openModal('batch-override-domain')}
        disabled={selectionOverLimit}
      >
        일괄 도메인
      </Button>
      <Button
        variant="secondary"
        size="sm"
        onclick={() => ui.openModal('batch-override-tag')}
        disabled={selectionOverLimit}
      >
        일괄 태그
      </Button>
    </div>
  {/if}

  <!-- 목록 -->
  {#if loading}
    <div class="space-y-3">
      {#each Array(3) as _}
        <Skeleton h="h-28" rounded="card" />
      {/each}
    </div>
  {:else if filteredDocs.length === 0}
    <EmptyState
      icon={InboxIcon}
      title={documents.length === 0 ? 'Inbox가 비어 있습니다' : '필터 결과 없음'}
      description={documents.length === 0
        ? '새 파일이 들어오면 자동으로 표시됩니다.'
        : '필터를 조정해 보세요.'}
    />
  {:else}
    <div class="space-y-3">
      {#each filteredDocs as doc (doc.id)}
        {@const approvable = isApprovable(doc)}
        {@const isChecked = selected.has(doc.id)}
        {@const ov = overrides.get(doc.id) ?? {}}
        {@const displayDomain = effectiveDomain(doc)}
        {@const displayTags = effectiveTags(doc)}
        {@const hasOverride = ov.domain !== undefined || ov.tags !== undefined}
        <Card class={approvable ? '' : 'border-warning/50'}>
          <div class="flex items-start gap-3">
            <input
              type="checkbox"
              checked={isChecked}
              disabled={!approvable}
              onchange={() => toggleSelect(doc.id)}
              class="mt-1 h-4 w-4 accent-accent disabled:opacity-40 disabled:cursor-not-allowed"
              aria-label="{doc.title || '문서'} 선택"
            />
            <div class="flex-1 min-w-0">
              <!-- 제목 + 미분류 경고 -->
              <div class="flex items-center gap-2 mb-1 flex-wrap">
                <span class="text-faint"><FormatIcon format={doc.file_format} size={14} /></span>
                <a
                  href="/documents/{doc.id}"
                  class="text-sm font-medium text-text hover:text-accent truncate"
                >
                  {doc.title || '제목 없음'}
                </a>
                {#if !approvable}
                  <Badge tone="warning" size="sm">
                    <AlertTriangle size={10} />
                    도메인 선택 필요
                  </Badge>
                {/if}
                {#if hasOverride}
                  <Badge tone="accent" size="sm">override</Badge>
                {/if}
              </div>
              {#if doc.ai_summary}
                <p class="text-xs text-dim truncate mb-2">{doc.ai_summary.slice(0, 140)}</p>
              {/if}

              <!-- F.4 처리 단계 타임스탬프 -->
              <div class="flex items-center gap-1.5 mb-2 flex-wrap">
                <Badge tone={doc.extracted_at ? 'success' : 'neutral'} size="sm">
                  {#if doc.extracted_at}<CheckCircle2 size={10} />{/if}
                  추출
                </Badge>
                <Badge tone={doc.ai_processed_at ? 'success' : 'neutral'} size="sm">
                  {#if doc.ai_processed_at}<CheckCircle2 size={10} />{/if}
                  분류
                </Badge>
                <Badge tone={doc.embedded_at ? 'success' : 'neutral'} size="sm">
                  {#if doc.embedded_at}<CheckCircle2 size={10} />{/if}
                  임베딩
                </Badge>
                <span class="text-[10px] text-faint">
                  · {doc.source_channel || '-'}
                </span>
              </div>

              <!-- F.5 행별 override -->
              <div class="flex items-center gap-2 flex-wrap">
                <span class="text-[10px] text-dim shrink-0">도메인</span>
                <select
                  aria-label="도메인 선택"
                  value={displayDomain}
                  onchange={(e) => setDomainOverride(doc.id, e.currentTarget.value)}
                  class="text-xs px-2 py-1 rounded bg-bg border border-default text-text focus:border-accent outline-none"
                >
                  <option value="">미분류</option>
                  {#each DOMAIN_OPTIONS as opt}
                    <option value={opt.value}>{opt.label}</option>
                  {/each}
                </select>
                {#if hasOverride}
                  <button
                    type="button"
                    onclick={() => clearOverride(doc.id)}
                    class="inline-flex items-center gap-1 text-[10px] text-dim hover:text-accent"
                    title="override 초기화"
                  >
                    <RotateCcw size={10} />
                    원복
                  </button>
                {/if}
                {#if displayTags.length > 0}
                  <div class="flex gap-1 ml-2 flex-wrap">
                    {#each displayTags.slice(0, 6) as tag}
                      <TagPill {tag} clickable={false} />
                    {/each}
                  </div>
                {/if}
              </div>
            </div>
          </div>
        </Card>
      {/each}
    </div>
  {/if}
</div>

<!-- 승인 확인 -->
<ConfirmDialog
  id="approve-confirm"
  title="{selectionCount}건 승인"
  message="선택한 문서를 승인합니다. 도메인/태그 override가 있으면 함께 저장됩니다."
  confirmLabel="승인"
  tone="primary"
  loading={busy}
  onconfirm={confirmApprove}
/>

<!-- 배치 도메인 override -->
<Modal id="batch-override-domain" title="일괄 도메인 override" size="sm">
  <p class="text-xs text-dim mb-3">
    선택한 {selectionCount}건에 로컬 override 적용. 아직 저장되지 않음 — 승인 시 반영됨.
  </p>
  <Select
    bind:value={batchDomainValue}
    options={DOMAIN_OPTIONS}
    placeholder="도메인 선택"
    label="도메인"
  />
  {#snippet footer()}
    <Button variant="ghost" size="sm" onclick={() => ui.closeModal('batch-override-domain')}>
      취소
    </Button>
    <Button
      variant="primary"
      size="sm"
      disabled={!batchDomainValue}
      onclick={applyBatchDomain}
    >
      적용
    </Button>
  {/snippet}
</Modal>

<!-- 배치 태그 override -->
<Modal id="batch-override-tag" title="일괄 태그 추가" size="sm">
  <p class="text-xs text-dim mb-3">
    선택한 {selectionCount}건에 태그 override. 이미 같은 태그는 skip.
  </p>
  <TextInput bind:value={batchTagValue} placeholder="태그 입력" label="태그" />
  {#snippet footer()}
    <Button variant="ghost" size="sm" onclick={() => ui.closeModal('batch-override-tag')}>
      취소
    </Button>
    <Button
      variant="primary"
      size="sm"
      disabled={!batchTagValue.trim()}
      onclick={applyBatchTag}
    >
      적용
    </Button>
  {/snippet}
</Modal>
