<script lang="ts">
  import type { PageData } from './$types';
  import { tick } from 'svelte';

  // --- 상태 변수 ---
  export let data: PageData;
  let dataNumbers: DataNumberInfo[] = [];
  let rectangles: Rectangle[] = [];
  let selectedMovie: number | null = null;
  let selectedDataNumberInfo: DataNumberInfo | null = null;
  let isLoadingDataNumbers = false;
  let isLoadingImage = false;
  let imageHasError = false;

  // --- 상호작용 상태 변수 ---
  let selectedRectIds: number[] = []; 
  let imageElement: HTMLImageElement;
  let svgElement: SVGSVGElement;
  let activeInteraction: {
      type: 'move' | 'resize';
      handle?: string;
      startX: number;
      startY: number;
      initialRects?: Rectangle[]; 
  } | null = null;
  
  let dataNumberPanel: HTMLDivElement;
  let clipboard: Omit<Rectangle, 'id'>[] | null = null;

  // --- 반응형 로직 ---
  let selectedRectangles: Rectangle[] = [];
  $: selectedRectangles = rectangles.filter(r => selectedRectIds.includes(r.id));


  $: if (selectedDataNumberInfo) {
    imageHasError = false;
    selectedRectIds = []; // 이미지 변경 시 선택 해제
    // clipboard = null; 

    if (dataNumberPanel) {
        const selectedElement = dataNumberPanel.querySelector(`[data-index="${selectedDataNumberInfo.Index}"]`);
        if (selectedElement) {
            const containerRect = dataNumberPanel.getBoundingClientRect();
            const elementRect = selectedElement.getBoundingClientRect();
            if (elementRect.top < containerRect.top || elementRect.bottom > containerRect.bottom) {
                selectedElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
            }
        }
    }
  }

  // --- 데이터 로딩 함수 ---
  async function selectMovie(movieIndex: number) {
    if (selectedMovie === movieIndex) return;
    selectedMovie = movieIndex;
    selectedDataNumberInfo = null;
    rectangles = [];
    dataNumbers = [];
    isLoadingDataNumbers = true;
    try {
      const response = await fetch(`/api/datanumbers/${movieIndex}`);
      if (!response.ok) throw new Error('Failed to fetch data numbers');
      dataNumbers = await response.json();
    } catch (error) {
      console.error(error);
      alert((error as Error).message);
    } finally {
      isLoadingDataNumbers = false;
    }
   }

  async function selectDataNumber(dataInfo: DataNumberInfo) {
    if (selectedDataNumberInfo?.Index === dataInfo.Index || isLoadingImage) return;
    isLoadingImage = true;
    selectedRectIds = [];
    try {
        const preloadImagePromise = new Promise((resolve, reject) => {
            const img = new Image();
            img.onload = () => resolve(true);
            img.onerror = () => reject(new Error('Image preloading failed'));
            img.src = `/api/images/${dataInfo.LocationFile}`;
        });
        const fetchRectsPromise = fetch(`/api/rectangles/by-ref/${dataInfo.Index}`);
        const [_, response] = await Promise.all([preloadImagePromise, fetchRectsPromise]);
        if (!response.ok) throw new Error('Failed to fetch rectangles');
        const newRects = await response.json();
        rectangles = newRects;
        selectedDataNumberInfo = dataInfo;
        await tick();
        const newButton = dataNumberPanel?.querySelector(`li[data-index="${dataInfo.Index}"] button`) as HTMLElement;
        newButton?.focus();
    } catch (error) {
        console.error(error);
        alert((error as Error).message);
    } finally {
        isLoadingImage = false;
    }
  }

  // --- 사각형 CRUD 함수 ---
  async function addNewRectangle() {
    if (!selectedDataNumberInfo) return;
    const defaultRect = { x: 10, y: 10, width: 100, height: 100 };
    try {
        const url = `/api/rectangles/by-ref/${selectedDataNumberInfo.Index}`;
        const response = await fetch(url, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(defaultRect),
        });
        if (!response.ok) {
            const errorBody = await response.text();
            throw new Error(`Failed to create rectangle on server: ${errorBody}`);
        }
        const newRectFromServer = await response.json();
        const finalNewRect = { ...defaultRect, id: newRectFromServer.id };
        rectangles = [...rectangles, finalNewRect];
        selectedRectIds = [finalNewRect.id];
    } catch (error) {
        console.error(error);
        alert((error as Error).message);
    }
  }

  async function saveRectangle(rect: Rectangle) {
    const url = `/api/rectangles/by-id/${rect.id}`;
    try {
      const response = await fetch(url, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(rect),
      });
      if (!response.ok) throw new Error('Failed to save rectangle');
    } catch (error) {
      console.error(error);
      alert((error as Error).message);
    }
  }

  async function deleteSelectedRect() {
    if (selectedRectIds.length === 0) return;
    //if (!confirm(`Are you sure you want to delete ${selectedRectIds.length} rectangle(s)?`)) return;

    const idsToDelete = [...selectedRectIds]; // 나중에 사용하기 위해 ID 복사

    // UI에서 먼저 삭제 (Optimistic Update)
    rectangles = rectangles.filter(r => !idsToDelete.includes(r.id));
    selectedRectIds = [];

    try {
      // 서버에 모든 삭제 요청을 보냄
      await Promise.all(
        idsToDelete.map(id =>
          fetch(`/api/rectangles/by-id/${id}`, { method: 'DELETE' }).then(res => {
            if (!res.ok) throw new Error(`Failed to delete rectangle ${id}`);
          })
        )
      );
    } catch (error) {
      console.error(error);
      // 서버 삭제 실패 시 사용자에게 알림 (여기서는 콘솔에만 기록)
      // 필요하다면 UI 복구 로직을 추가할 수 있습니다.
    }
  }

  function copySelectedRect() {
    if (selectedRectangles.length === 0) {
      clipboard = null;
      return;
    }
    // 선택된 사각형들의 정보에서 id를 제외하고 복사
    clipboard = selectedRectangles.map(({ id, ...rest }) => rest);
  }

  async function pasteRect() {
    if (!clipboard || clipboard.length === 0 || !selectedDataNumberInfo) return;

    // 붙여넣을 사각형들의 데이터 준비 (기존 위치에서 살짝 이동)
    const newRectsData = clipboard.map(rect => ({
      x: rect.x + 10,
      y: rect.y + 10,
      width: rect.width,
      height: rect.height,
    }));

    try {
      const url = `/api/rectangles/by-ref/${selectedDataNumberInfo.Index}`;

      // 각 사각형 데이터에 대해 POST 요청을 보내고 모든 프로미스가 완료되길 기다림
      const createdRectsFromServer = await Promise.all(
        newRectsData.map(rectData =>
          fetch(url, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(rectData),
          }).then(async response => {
            if (!response.ok) {
              throw new Error(`Failed to create rectangle on server`);
            }
            // 서버는 생성된 객체의 id를 포함한 정보를 반환한다고 가정
            return response.json();
          })
        )
      );

      // 서버로부터 받은 id와 우리가 계산한 위치 정보를 합쳐 최종 객체 배열 생성
      const finalNewRects = newRectsData.map((rectData, index) => ({
        ...rectData,
        id: createdRectsFromServer[index].id,
      }));

      // UI 상태 업데이트
      rectangles = [...rectangles, ...finalNewRects];
      // 새로 붙여넣은 사각형들만 선택 상태로 변경
      selectedRectIds = finalNewRects.map(r => r.id);

    } catch (error) {
      console.error(error);
      alert((error as Error).message);
    }
  }

  // --- 이벤트 핸들러 ---
  function getMousePosition(event: MouseEvent) {
    if (!imageElement) return { x: 0, y: 0 };
    const svgRect = svgElement.getBoundingClientRect();
    const scaleX = svgElement.clientWidth / imageElement.naturalWidth;
    const scaleY = svgElement.clientHeight / imageElement.naturalHeight;
    return {
      x: (event.clientX - svgRect.left) / scaleX,
      y: (event.clientY - svgRect.top) / scaleY,
    };
  }

  function handleInteractionStart(event: MouseEvent, rect: Rectangle, type: 'move' | 'resize', handle: string) {
    event.stopPropagation();

    // --- 다중 선택 로직 시작 ---
    const alreadySelected = selectedRectIds.includes(rect.id);

    if (event.shiftKey) {
        // Shift 키를 누른 경우: 선택 토글
        if (alreadySelected) {
            // 이미 선택된 사각형이면 선택 해제
            selectedRectIds = selectedRectIds.filter(id => id !== rect.id);
        } else {
            // 선택되지 않은 사각형이면 선택 추가
            selectedRectIds = [...selectedRectIds, rect.id];
        }
    } else if (!alreadySelected) {
        // Shift 키 없이 아직 선택되지 않은 사각형을 클릭한 경우: 단일 선택
        selectedRectIds = [rect.id];
    }
    // Shift 키 없이 이미 선택된 사각형(그룹의 일부일 수 있음)을 클릭한 경우,
    // 선택 상태를 변경하지 않고 그대로 이동/리사이즈를 시작합니다.
    // --- 다중 선택 로직 끝 ---


    // 리사이즈는 단일 선택일 때만 활성화 (UI에서 이미 핸들이 보이지 않지만, 안전장치)
    if (type === 'resize' && selectedRectIds.length > 1) {
        return;
    }

    const pos = getMousePosition(event);
    activeInteraction = {
      type,
      handle,
      startX: pos.x,
      startY: pos.y,
      // 현재 선택된 모든 사각형의 초기 상태를 저장
      initialRects: rectangles
        .filter(r => selectedRectIds.includes(r.id))
        .map(r => ({ ...r })), // 복사본 저장
    };

    window.addEventListener('mousemove', handleMouseMove);
    window.addEventListener('mouseup', handleMouseUp);
  }

  function handleMouseMove(event: MouseEvent) {
    if (!activeInteraction || !activeInteraction.initialRects || activeInteraction.initialRects.length === 0) return;

    const pos = getMousePosition(event);
    const dx = pos.x - activeInteraction.startX;
    const dy = pos.y - activeInteraction.startY;
    
    // 리사이즈 로직 (단일 객체에만 적용됨)
    if (activeInteraction.type === 'resize') {
      const initialRect = activeInteraction.initialRects[0];
      const i = rectangles.findIndex(r => r.id === initialRect.id);
      if (i === -1) return;

      const { handle } = activeInteraction;
      let { x, y, width, height } = initialRect;

      if (handle!.includes('e')) width += dx;
      if (handle!.includes('w')) { width -= dx; x += dx; }
      if (handle!.includes('s')) height += dy;
      if (handle!.includes('n')) { height -= dy; y += dy; }
      
      if (width < 10) width = 10;
      if (height < 10) height = 10;
      
      rectangles[i] = { ...rectangles[i], x, y, width, height };

    } else if (activeInteraction.type === 'move') {
      // 이동 로직 (선택된 모든 객체에 적용)
      activeInteraction.initialRects.forEach(initialRect => {
        const i = rectangles.findIndex(r => r.id === initialRect.id);
        if (i !== -1) {
            rectangles[i] = {
                ...rectangles[i],
                x: initialRect.x + dx,
                y: initialRect.y + dy,
            };
        }
      });
    }
  }

  function handleMouseUp() {
    if (activeInteraction && activeInteraction.initialRects) {
      // 변경된 모든 사각형을 찾아서 저장 요청
      const rectsToSave = rectangles.filter(r =>
        activeInteraction!.initialRects!.some(ir => ir.id === r.id)
      );
      // 여러 API 요청을 동시에 보냄
      Promise.all(rectsToSave.map(rect => saveRectangle(rect)));
    }
    activeInteraction = null;
    window.removeEventListener('mousemove', handleMouseMove);
    window.removeEventListener('mouseup', handleMouseUp);
  }

  function deselectRect(event: MouseEvent) {
    if (event.target === svgElement) {
        selectedRectIds = []; // 빈 배열로 만들어 선택 해제
    }
  }

  // 키보드 이벤트 핸들러에 복사/붙여넣기 추가
  function handleKeyDown(event: KeyboardEvent) {
    if (event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement) {
        return;
    }

    if (event.ctrlKey || event.metaKey) {
        if (event.key.toLowerCase() === 'c') {
            event.preventDefault();
            copySelectedRect();
            return;
        }
        if (event.key.toLowerCase() === 'v') {
            event.preventDefault();
            pasteRect();
            return;
        }
    }
    
    if (!selectedDataNumberInfo || dataNumbers.length <= 1) return;
    const currentIndex = dataNumbers.findIndex(d => d.Index === selectedDataNumberInfo!.Index);
    if (currentIndex === -1) return;
    let nextIndex = -1;
    switch (event.key) {
        case 'ArrowDown':
        case 'ArrowRight':
        case 'PageDown':
            event.preventDefault();
            if (currentIndex < dataNumbers.length - 1) nextIndex = currentIndex + 1;
            break;
        case 'ArrowUp':
        case 'ArrowLeft':
        case 'PageUp':
            event.preventDefault();
            if (currentIndex > 0) nextIndex = currentIndex - 1;
            break;
    }
    if (nextIndex !== -1) selectDataNumber(dataNumbers[nextIndex]);
  }

  const handles = ['n', 's', 'e', 'w', 'nw', 'ne', 'sw', 'se'];
</script>

<svelte:window on:keydown={handleKeyDown} />

<div class="flex w-full h-full">
  <!-- 1. 왼쪽: Movie Index 내비게이션 -->
  <nav class="w-[15%] min-w-[200px] bg-white p-4 border-r border-gray-200 overflow-y-auto">
    <div class="nav-section border border-gray-200 rounded-lg p-3">
      <h2 class="text-sm font-bold text-gray-600 uppercase tracking-wider mb-2 px-1">Movie Index</h2>
      <ul class="space-y-1">
        {#if data.movies && data.movies.length > 0}
          {#each data.movies as movie}
            <li>
              <button
                on:click={() => selectMovie(movie)}
                class="w-full text-left px-3 py-2 rounded-md text-gray-700 transition-colors duration-150"
                class:bg-blue-500={selectedMovie === movie}
                class:text-white={selectedMovie === movie}
                class:hover:bg-gray-100={selectedMovie !== movie}
              >
                {movie}
              </button>
            </li>
          {/each}
        {:else if data.error}
          <p class="text-sm text-red-500 px-3">{data.error}</p>
        {:else}
          <p class="text-sm text-gray-500 px-3">No movies found.</p>
        {/if}
      </ul>
    </div>
  </nav>

  <!-- 2. 중앙: Data Number 목록 -->
  <div bind:this={dataNumberPanel} class="w-[15%] min-w-[200px] bg-gray-50 p-4 border-r border-gray-200 overflow-y-auto">
    {#if selectedMovie}
      <div class="nav-section border border-gray-200 rounded-lg p-3 bg-white">
        <h2 class="text-sm font-bold text-gray-600 uppercase tracking-wider mb-2 px-1">Data Number</h2>
        {#if isLoadingDataNumbers}
          <p class="text-sm text-gray-500 px-3">Loading...</p>
        {:else if dataNumbers.length > 0}
          <ul class="space-y-1">
            {#each dataNumbers as dataInfo (dataInfo.Index)}
              <li data-index={dataInfo.Index}>
                <button
                  on:click={() => selectDataNumber(dataInfo)}
                  class="w-full text-left px-3 py-2 rounded-md text-gray-700 transition-colors duration-150"
                  class:bg-green-500={selectedDataNumberInfo?.Index === dataInfo.Index}
                  class:text-white={selectedDataNumberInfo?.Index === dataInfo.Index}
                  class:hover:bg-gray-100={selectedDataNumberInfo?.Index !== dataInfo.Index}
                >
                  {dataInfo.DataNumber}
                </button>
              </li>
            {/each}
          </ul>
        {:else}
          <p class="text-sm text-gray-500 px-3">No data found.</p>
        {/if}
      </div>
    {:else}
      <div class="text-center text-gray-400 text-sm mt-4">
        <p>Select a Movie Index to see data numbers.</p>
      </div>
    {/if}
  </div>

  <!-- 3. 오른쪽: 이미지 뷰어 및 툴바 -->
  <div class="w-[70%] flex flex-col bg-gray-200">
    <!-- 툴바에 Copy/Paste 버튼 추가 -->
    <div class="flex-shrink-0 p-2 bg-white border-b border-gray-300 shadow-sm flex items-center gap-4">
        <div>
            <button on:click={addNewRectangle} disabled={!selectedDataNumberInfo}
              class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed">
              Add Rectangle
            </button>
            <button on:click={copySelectedRect} disabled={selectedRectangles.length === 0}
              class="ml-2 px-4 py-2 text-sm font-medium text-white bg-indigo-600 rounded-md hover:bg-indigo-700 disabled:bg-gray-400 disabled:cursor-not-allowed">
              Copy
            </button>
            <button on:click={pasteRect} disabled={!clipboard || clipboard.length === 0}
              class="ml-2 px-4 py-2 text-sm font-medium text-white bg-purple-600 rounded-md hover:bg-purple-700 disabled:bg-gray-400 disabled:cursor-not-allowed">
              Paste
            </button>
            <button on:click={deleteSelectedRect} disabled={selectedRectangles.length === 0}
              class="ml-2 px-4 py-2 text-sm font-medium text-white bg-red-600 rounded-md hover:bg-red-700 disabled:bg-gray-400 disabled:cursor-not-allowed">
              Delete Selected
            </button>
        </div>
        {#if selectedRectangles.length === 1}
            {@const selectedRectangle = selectedRectangles[0]}
            <div class="text-xs text-gray-600 border-l-2 border-gray-300 pl-4 flex items-center gap-3">
                <span class="font-mono"><strong class="font-bold text-gray-800">ID:</strong> {selectedRectangle.id}</span>
                <span class="font-mono"><strong class="font-bold text-gray-800">X1:</strong> {Math.round(selectedRectangle.x)}</span>
                <span class="font-mono"><strong class="font-bold text-gray-800">Y1:</strong> {Math.round(selectedRectangle.y)}</span>
                <span class="font-mono"><strong class="font-bold text-gray-800">X2:</strong> {Math.round(selectedRectangle.x + selectedRectangle.width)}</span>
                <span class="font-mono"><strong class="font-bold text-gray-800">Y2:</strong> {Math.round(selectedRectangle.y + selectedRectangle.height)}</span>
            </div>
        {/if}
    </div>

    <!-- 뷰어 -->
    <div class="flex-grow p-6 overflow-auto flex justify-center items-center">
      {#if !selectedDataNumberInfo}
        <div class="text-center text-gray-500"><p>Select a data number to view the image.</p></div>
      {:else}
        <div class="relative max-w-full max-h-full shadow-lg bg-white image-viewer-container">
          {#if !imageHasError}
              <img bind:this={imageElement} src={`/api/images/${selectedDataNumberInfo.LocationFile}`} alt={`Data ${selectedDataNumberInfo.DataNumber}`} class="block max-w-full max-h-[calc(100vh-180px)] object-contain" on:error={() => imageHasError = true} />
          {/if}
          
          <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
          <svg bind:this={svgElement} class="absolute top-0 left-0 w-full h-full" on:mousedown|self={deselectRect} role="region" aria-label="Image annotation area">
            {#if !imageHasError}
              {#each rectangles as rect (rect.id)}
                {@const isSelected = selectedRectIds.includes(rect.id)}
                <rect
                  x={rect.x} y={rect.y} width={rect.width} height={rect.height}
                  role="button"
                  tabindex="0"
                  aria-label="Annotation {rect.id}"
                  class="fill-yellow-400/20 stroke-yellow-400 stroke-2"
                  class:selected={isSelected} class:cursor-move={isSelected}
                  on:mousedown|stopPropagation={(e) => handleInteractionStart(e, rect, 'move', 'body')}
                />
                {#if selectedRectangles.length === 1 && selectedRectangles[0].id === rect.id}
                  {#each handles as handle}
                    {@const handleX = handle.includes('w') ? rect.x : (handle.includes('e') ? rect.x + rect.width : rect.x + rect.width / 2)}
                    {@const handleY = handle.includes('n') ? rect.y : (handle.includes('s') ? rect.y + rect.height : rect.y + rect.height / 2)}
                    <rect
                      x={handleX - 4} y={handleY - 4} width="8" height="8"
                      role="button"
                      tabindex="0"
                      aria-label="Resize handle {handle}"
                      class="fill-white stroke-blue-600 stroke-2 cursor-{handle}-resize"
                      on:mousedown|stopPropagation={(e) => handleInteractionStart(e, rect, 'resize', handle)}
                    />
                  {/each}
                {/if}
              {/each}
            {/if}
          </svg>

        </div>
      {/if}
    </div>
  </div>
</div>

<style>
  .image-viewer-container {
      user-select: none; /* 사용자의 텍스트 드래그 및 더블클릭 선택을 비활성화합니다. */
      -webkit-user-select: none; /* Safari, Chrome 등 웹킷 브라우저 호환성 */
      -moz-user-select: none;    /* Firefox 호환성 */
      -ms-user-select: none;     /* IE, Edge 호환성 */
    }

    rect.selected {
        stroke: #0ea5e9; /* 눈에 띄는 하늘색 (sky-500) */
        stroke-width: 3px; /* 테두리 굵게 */
        stroke-dasharray: 6 3; /* 점선 스타일로 변경 */
    }

    /* TailwindCSS JIT 컴파일러가 동적 클래스 이름을 인식하도록 커서 스타일을 미리 정의합니다. */
    .cursor-n-resize { cursor: n-resize; }
    .cursor-s-resize { cursor: s-resize; }
    /* TailwindCSS JIT 컴파일러가 동적 클래스 이름을 인식하도록 커서 스타일을 미리 정의합니다. */
    .cursor-n-resize { cursor: n-resize; }
    .cursor-s-resize { cursor: s-resize; }
    .cursor-e-resize { cursor: e-resize; }
    .cursor-w-resize { cursor: w-resize; }
    .cursor-nw-resize { cursor: nw-resize; }
    .cursor-ne-resize { cursor: ne-resize; }
    .cursor-sw-resize { cursor: sw-resize; }
    .cursor-se-resize { cursor: se-resize; }
</style>
