<script>
  import { onDestroy, onMount } from 'svelte';
  import { uploadFile } from '$lib/api';
  import { addToast } from '$lib/stores/toast';
  import { publicConfig } from '$lib/stores/config';
  import { Upload, X } from 'lucide-svelte';

  let { onupload = () => {} } = $props();

  // 업로드 크기 한도는 서버 `upload.max_bytes` 가 authoritative. 여기서는 pre-check UX 용으로만 사용.
  // 실제 enforcement 는 /documents/ POST 413 응답 (서버 스트리밍 검증) 이 담당.
  const maxBytes = $derived($publicConfig.upload.max_bytes);
  const maxBytesLabel = $derived(formatSize($publicConfig.upload.max_bytes));
  const NAS_FALLBACK_HINT = '대용량 파일은 Synology Drive 의 PKM/Inbox 폴더에 두면 자동 수집 대상이 됩니다.';

  let dragging = $state(false);
  let uploading = $state(false);
  // uploadFiles[i]: { name, size, status, loaded, total, controller, errorCode? }
  let uploadFiles = $state([]);
  let dragCounter = 0;

  // 페이지 이탈 경고 (업로드 진행 중일 때만)
  function onBeforeUnload(e) {
    if (uploading && uploadFiles.some(f => f.status === 'uploading')) {
      e.preventDefault();
      e.returnValue = '';
      return '';
    }
  }

  function formatSize(bytes) {
    if (bytes >= 1_000_000_000) return `${(bytes / 1_000_000_000).toFixed(1)}GB`;
    if (bytes >= 1_000_000) return `${Math.round(bytes / 1_000_000)}MB`;
    return `${Math.round(bytes / 1000)}KB`;
  }

  function errorMessage(err, fileName) {
    // err: ApiError { status, detail (string), errorCode?, errorMessage? }
    const code = err && err.errorCode;
    if (code) {
      switch (code) {
        case 'body_too_large':
          return `${fileName}: ${maxBytesLabel} 초과. ${NAS_FALLBACK_HINT}`;
        case 'upload_timeout':
          return `${fileName}: 업로드 시간 초과 — 네트워크 확인 후 재시도`;
        case 'network_abort':
          return `${fileName}: 업로드 취소됨`;
        case 'empty_file':
          return `${fileName}: 빈 파일은 업로드 불가`;
        case 'invalid_input':
          return `${fileName}: ${err.errorMessage || '입력값 오류'}`;
        case 'unsupported_codec':
          return `${fileName}: ${err.errorMessage || 'mp4(H.264)/webm 으로 변환 후 업로드'}`;
        case 'internal':
          return `${fileName}: 서버 오류 — 잠시 후 재시도`;
        default:
          return `${fileName}: ${err.errorMessage || code}`;
      }
    }
    if (err && err.status === 413) {
      return `${fileName}: 서버 거절 (Payload Too Large). ${NAS_FALLBACK_HINT}`;
    }
    if (err && err.status === 401) {
      return `${fileName}: 인증 만료 — 다시 로그인하세요`;
    }
    return `${fileName}: ${(err && err.detail) || '업로드 실패'}`;
  }

  onMount(() => {
    function onDragEnter(e) {
      e.preventDefault();
      e.stopPropagation();
      dragCounter++;
      dragging = true;
    }
    function onDragOver(e) {
      e.preventDefault();
      e.stopPropagation();
    }
    function onDragLeave(e) {
      e.preventDefault();
      e.stopPropagation();
      dragCounter--;
      if (dragCounter <= 0) {
        dragging = false;
        dragCounter = 0;
      }
    }
    function onDrop(e) {
      e.preventDefault();
      e.stopPropagation();
      dragging = false;
      dragCounter = 0;
      handleFiles(e.dataTransfer?.files);
    }

    window.addEventListener('dragenter', onDragEnter);
    window.addEventListener('dragover', onDragOver);
    window.addEventListener('dragleave', onDragLeave);
    window.addEventListener('drop', onDrop);
    window.addEventListener('beforeunload', onBeforeUnload);

    return () => {
      window.removeEventListener('dragenter', onDragEnter);
      window.removeEventListener('dragover', onDragOver);
      window.removeEventListener('dragleave', onDragLeave);
      window.removeEventListener('drop', onDrop);
      window.removeEventListener('beforeunload', onBeforeUnload);
    };
  });

  onDestroy(() => {
    // 컴포넌트 언마운트 시 진행 중 업로드 abort
    uploadFiles.forEach(f => {
      if (f.status === 'uploading' && f.controller) f.controller.abort();
    });
  });

  function abortFile(index) {
    const f = uploadFiles[index];
    if (f && f.status === 'uploading' && f.controller) {
      f.controller.abort();
    }
  }

  function abortAll() {
    uploadFiles.forEach((f, i) => {
      if (f.status === 'uploading') abortFile(i);
    });
  }

  async function handleFiles(fileList) {
    const allFiles = Array.from(fileList || []);
    if (allFiles.length === 0) return;

    // 사전 크기 검사 — 서버 한도 초과는 즉시 차단 + Drive 안내
    const tooLarge = allFiles.filter(f => f.size > maxBytes);
    const files = allFiles.filter(f => f.size <= maxBytes);

    if (tooLarge.length > 0) {
      const names = tooLarge
        .map(f => `${f.name} (${formatSize(f.size)})`)
        .join(', ');
      addToast(
        'error',
        `${maxBytesLabel} 초과 파일은 업로드 불가 (${tooLarge.length}건: ${names}). ${NAS_FALLBACK_HINT}`,
        10000
      );
    }

    if (files.length === 0) return;

    uploading = true;
    uploadFiles = files.map(f => ({
      name: f.name,
      size: f.size,
      status: 'pending',
      loaded: 0,
      total: f.size,
      controller: null,
    }));

    let success = 0;
    let failed = 0;
    let aborted = 0;

    for (let i = 0; i < files.length; i++) {
      const controller = new AbortController();
      uploadFiles[i] = { ...uploadFiles[i], status: 'uploading', controller };
      uploadFiles = [...uploadFiles];

      try {
        const formData = new FormData();
        formData.append('file', files[i]);
        await uploadFile('/documents/', formData, {
          signal: controller.signal,
          onProgress: (loaded, total) => {
            uploadFiles[i] = { ...uploadFiles[i], loaded, total };
            uploadFiles = [...uploadFiles];
          },
        });
        uploadFiles[i] = { ...uploadFiles[i], status: 'done', controller: null };
        uploadFiles = [...uploadFiles];
        success++;
      } catch (err) {
        const code = err && err.errorCode ? err.errorCode : null;
        const isAbort = code === 'network_abort';
        uploadFiles[i] = {
          ...uploadFiles[i],
          status: isAbort ? 'aborted' : 'failed',
          controller: null,
          errorCode: code,
        };
        uploadFiles = [...uploadFiles];
        if (isAbort) {
          aborted++;
        } else {
          failed++;
          addToast('error', errorMessage(err, files[i].name), 10000);
        }
      }
    }

    const tail =
      (failed > 0 ? `, ${failed}건 실패` : '') +
      (aborted > 0 ? `, ${aborted}건 취소` : '') +
      (tooLarge.length > 0 ? `, ${tooLarge.length}건 용량 초과 스킵` : '');

    if (success > 0) {
      addToast('success', `${success}건 업로드 완료${tail}`);
      onupload();
    } else if (failed > 0) {
      addToast('error', `업로드 실패 (${failed}건)${tail}`);
    } else if (aborted > 0) {
      addToast('info', `업로드 취소됨 (${aborted}건)${tail}`);
    }

    setTimeout(() => {
      uploading = false;
      uploadFiles = [];
    }, 3000);
  }

  function pct(f) {
    if (!f.total) return 0;
    return Math.min(100, Math.round((f.loaded / f.total) * 100));
  }
</script>

<!-- 전체 페이지 드래그 오버레이 -->
{#if dragging}
  <div class="fixed inset-0 z-50 bg-accent/10 border-2 border-dashed border-accent flex items-center justify-center">
    <div class="bg-surface rounded-xl px-8 py-6 shadow-xl text-center">
      <Upload size={32} class="mx-auto mb-2 text-accent" />
      <p class="text-sm font-medium text-accent">여기에 파일을 놓으세요</p>
      <p class="text-xs text-dim mt-1">최대 {maxBytesLabel}</p>
    </div>
  </div>
{/if}

<!-- 업로드 진행 상태 -->
{#if uploading && uploadFiles.length > 0}
  <div class="mb-3 bg-surface border border-default rounded-lg p-3">
    <div class="flex items-center justify-between mb-2">
      <p class="text-xs text-dim">업로드 중...</p>
      {#if uploadFiles.some(f => f.status === 'uploading')}
        <button
          type="button"
          class="text-xs text-dim hover:text-error underline underline-offset-2"
          onclick={abortAll}
        >
          전부 취소
        </button>
      {/if}
    </div>
    <div class="space-y-2 max-h-48 overflow-y-auto">
      {#each uploadFiles as f, i}
        <div class="text-xs">
          <div class="flex items-center justify-between gap-2">
            <span class="truncate flex-1">{f.name}</span>
            <span class="text-dim shrink-0">{formatSize(f.size)}</span>
            <span class={
              f.status === 'done' ? 'text-success' :
              f.status === 'failed' ? 'text-error' :
              f.status === 'aborted' ? 'text-dim' :
              f.status === 'uploading' ? 'text-accent' :
              'text-dim'
            }>
              {f.status === 'done' ? '✓' :
                f.status === 'failed' ? '✗' :
                f.status === 'aborted' ? '⊘' :
                f.status === 'uploading' ? `${pct(f)}%` : '…'}
            </span>
            {#if f.status === 'uploading'}
              <button
                type="button"
                class="text-dim hover:text-error"
                title="이 파일 업로드 취소"
                onclick={() => abortFile(i)}
              >
                <X size={12} />
              </button>
            {/if}
          </div>
          {#if f.status === 'uploading'}
            <div class="h-1 w-full bg-default/20 rounded mt-1 overflow-hidden">
              <div class="h-full bg-accent transition-all" style="width: {pct(f)}%"></div>
            </div>
          {/if}
        </div>
      {/each}
    </div>
  </div>
{/if}
