import React, { useEffect, useRef, useState } from "react";
import {
  isPageOrderDirty,
  movePageInList,
  pagePreviewSnapshot,
} from "../../utils/documentPageForm.js";

function pageKey(pageForm, index) {
  if (pageForm.page_id != null) return `page-${pageForm.page_id}`;
  return pageForm._localId || `draft-${index}`;
}

function insertionPoint(rects, insertAt) {
  const n = rects.length;
  if (!n) return null;

  if (insertAt <= 0) {
    const first = rects[0];
    return { x: first.left - 4, y: first.top + first.height / 2 };
  }

  if (insertAt >= n) {
    const last = rects[n - 1];
    return { x: last.right + 4, y: last.top + last.height / 2 };
  }

  const before = rects[insertAt - 1];
  const after = rects[insertAt];
  const sameRow = Math.abs(before.top - after.top) < 12;

  if (sameRow) {
    return {
      x: (before.right + after.left) / 2,
      y: (before.top + before.bottom) / 2,
    };
  }

  return {
    x: after.left + after.width / 2,
    y: after.top + after.height / 2,
  };
}

function resolveInsertAt(event, items, total, dragIndex) {
  const nodes = Array.from(items);
  if (!nodes.length) return 0;

  const rects = nodes.map((node) => node.getBoundingClientRect());
  const pad = 6;

  for (let i = 0; i < nodes.length; i += 1) {
    const rect = rects[i];
    const inside =
      event.clientX >= rect.left - pad &&
      event.clientX <= rect.right + pad &&
      event.clientY >= rect.top - pad &&
      event.clientY <= rect.bottom + pad;

    if (!inside) continue;

    // Forward drag: dropping on a page means "take this page's slot".
    if (dragIndex != null && dragIndex < i) {
      return i + 1;
    }

    // Backward drag: insert before the hovered page.
    if (dragIndex != null && dragIndex > i) {
      return i;
    }

    const midX = rect.left + rect.width / 2;
    const midY = rect.top + rect.height / 2;
    if (event.clientY < midY) return i;
    if (event.clientX < midX) return i;
    return i + 1;
  }

  let best = total;
  let bestScore = Infinity;
  for (let i = 0; i <= rects.length; i += 1) {
    const pt = insertionPoint(rects, i);
    if (!pt) continue;
    const dx = event.clientX - pt.x;
    const dy = event.clientY - pt.y;
    const score = dx * dx + dy * dy;
    if (score < bestScore) {
      bestScore = score;
      best = i;
    }
  }

  return best;
}

/** Convert "insert before insertAt" to splice index after the dragged item is removed. */
function resolveDropIndex(fromIndex, insertAt, total) {
  if (fromIndex == null || insertAt == null) return null;
  let toIndex = fromIndex < insertAt ? insertAt - 1 : insertAt;
  if (toIndex === fromIndex) return null;
  if (toIndex < 0 || toIndex >= total) return null;
  return toIndex;
}

function PageThumbnail({ pageForm, pageIndex, isDragging, isActive }) {
  const preview = pagePreviewSnapshot(pageForm, pageIndex);

  return (
    <div
      className={`doc-page-filmstrip__thumb${isDragging ? " is-dragging" : ""}${isActive ? " is-active" : ""}`}
    >
      <div className="doc-page-filmstrip__paper" aria-hidden>
        <div className="doc-page-filmstrip__paper-head">
          <span className="doc-page-filmstrip__paper-line doc-page-filmstrip__paper-line--short" />
          <span className="doc-page-filmstrip__paper-line" />
          <span className="doc-page-filmstrip__paper-line doc-page-filmstrip__paper-line--medium" />
        </div>
        <div className="doc-page-filmstrip__paper-body">
          {preview.previewImage ? (
            <img
              className="doc-page-filmstrip__paper-image"
              src={preview.previewImage}
              alt=""
              draggable={false}
            />
          ) : preview.snippet ? (
            <p className="doc-page-filmstrip__paper-text">{preview.snippet}</p>
          ) : (
            <p className="doc-page-filmstrip__paper-empty">Blank page</p>
          )}
        </div>
        {preview.logoCount > 0 || preview.imageCount > 0 ? (
          <div className="doc-page-filmstrip__paper-meta">
            {preview.imageCount > 0
              ? `${preview.imageCount} image${preview.imageCount === 1 ? "" : "s"}`
              : null}
            {preview.logoCount > 0
              ? `${preview.logoCount} logo${preview.logoCount === 1 ? "" : "s"}`
              : null}
          </div>
        ) : null}
      </div>
      <span className="doc-page-filmstrip__page-num">{pageIndex + 1}</span>
    </div>
  );
}

/**
 * Collapsible page preview strip with drag-to-reorder.
 */
export default function PageOrderBar({
  pageForms,
  savedOrderSignature,
  disabled = false,
  onReorder,
  onResetOrder,
  onScrollToPage,
}) {
  const [panelOpen, setPanelOpen] = useState(false);
  const [dragIndex, setDragIndex] = useState(null);
  const [dropInsertAt, setDropInsertAt] = useState(null);
  const [activeIndex, setActiveIndex] = useState(0);

  const listRef = useRef(null);
  const scrollRef = useRef(null);
  const dragGhostRef = useRef(null);
  const pointerYRef = useRef(null);
  const pendingInsertRef = useRef(null);
  const dragRafRef = useRef(null);
  const dropInsertAtRef = useRef(null);

  const orderDirty = isPageOrderDirty(pageForms, savedOrderSignature);
  const canReorder = !disabled && pageForms.length > 1;

  useEffect(() => {
    const ghost = document.createElement("div");
    ghost.setAttribute("aria-hidden", "true");
    ghost.style.cssText =
      "position:fixed;top:-9999px;left:-9999px;width:1px;height:1px;opacity:0;pointer-events:none";
    document.body.appendChild(ghost);
    dragGhostRef.current = ghost;
    return () => ghost.remove();
  }, []);

  useEffect(() => {
    if (dragIndex == null) return undefined;

    let frameId = 0;
    const autoScroll = () => {
      const scrollEl = scrollRef.current;
      const pointerY = pointerYRef.current;
      if (scrollEl && pointerY != null) {
        const edge = 56;
        const speed = 12;
        const { top, bottom } = scrollEl.getBoundingClientRect();
        if (pointerY < top + edge) {
          scrollEl.scrollTop -= speed;
        } else if (pointerY > bottom - edge) {
          scrollEl.scrollTop += speed;
        }
      }
      frameId = requestAnimationFrame(autoScroll);
    };

    frameId = requestAnimationFrame(autoScroll);
    return () => cancelAnimationFrame(frameId);
  }, [dragIndex]);

  if (!pageForms?.length) {
    return null;
  }

  const notifyReorder = (nextPages) => {
    onReorder(nextPages);
  };

  const resolveDropIndexForDrag = (insertAt) =>
    resolveDropIndex(dragIndex, insertAt, pageForms.length);

  const commitDrop = (insertAt) => {
    const toIndex = resolveDropIndexForDrag(insertAt);
    if (toIndex == null) return;
    notifyReorder(movePageInList(pageForms, dragIndex, toIndex));
  };

  const move = (fromIndex, toIndex) => {
    if (fromIndex === toIndex) return;
    notifyReorder(movePageInList(pageForms, fromIndex, toIndex));
    setActiveIndex(toIndex);
  };

  const clearDragState = () => {
    setDragIndex(null);
    setDropInsertAt(null);
    dropInsertAtRef.current = null;
    pointerYRef.current = null;
    pendingInsertRef.current = null;
    if (dragRafRef.current) {
      cancelAnimationFrame(dragRafRef.current);
      dragRafRef.current = null;
    }
  };

  const scheduleDragUpdate = (event) => {
    pointerYRef.current = event.clientY;
    pendingInsertRef.current = event;

    if (dragRafRef.current) return;

    dragRafRef.current = requestAnimationFrame(() => {
      dragRafRef.current = null;
      const dragEvent = pendingInsertRef.current;
      const list = listRef.current;
      if (!dragEvent || !list || dragIndex == null) return;

      const items = list.querySelectorAll(".doc-page-filmstrip__item");
      let insertAt = resolveInsertAt(
        dragEvent,
        items,
        pageForms.length,
        dragIndex
      );

      if (insertAt === dragIndex || insertAt === dragIndex + 1) {
        insertAt = null;
      }

      dropInsertAtRef.current = insertAt;
      setDropInsertAt((prev) => (prev === insertAt ? prev : insertAt));
    });
  };

  const onDragStart = (index) => (e) => {
    if (!canReorder) {
      e.preventDefault();
      return;
    }
    setDragIndex(index);
    e.dataTransfer.effectAllowed = "move";
    e.dataTransfer.setData("text/plain", String(index));
    if (dragGhostRef.current) {
      e.dataTransfer.setDragImage(dragGhostRef.current, 0, 0);
    }
  };

  const onDragOverList = (e) => {
    if (!canReorder || dragIndex == null) return;
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
    scheduleDragUpdate(e);
  };

  const onDropList = (e) => {
    e.preventDefault();
    if (!canReorder || dragIndex == null) return;
    const insertAt = dropInsertAtRef.current;
    if (insertAt != null) {
      commitDrop(insertAt);
    }
    clearDragState();
  };

  const onDragEnd = () => {
    clearDragState();
  };

  const jumpToPage = (index) => {
    setActiveIndex(index);
    onScrollToPage?.(index);
  };

  const panelClassName = [
    "doc-page-filmstrip",
    "doc-page-filmstrip--open",
    dragIndex != null ? "doc-page-filmstrip--dragging" : "",
    orderDirty ? "doc-page-filmstrip--dirty" : "",
  ]
    .filter(Boolean)
    .join(" ");

  if (!panelOpen) {
    return (
      <div
        className={`doc-page-filmstrip-launcher${orderDirty ? " doc-page-filmstrip-launcher--dirty" : ""}`}
      >
        <button
          type="button"
          className="doc-page-filmstrip-launcher__btn"
          disabled={disabled}
          onClick={() => setPanelOpen(true)}
          aria-expanded="false"
          aria-controls="doc-page-filmstrip-panel"
        >
          <span className="doc-page-filmstrip-launcher__icon" aria-hidden>
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <rect x="3" y="3" width="7" height="9" rx="1" />
              <rect x="14" y="3" width="7" height="9" rx="1" />
              <rect x="8.5" y="12" width="7" height="9" rx="1" />
            </svg>
          </span>
          <span className="doc-page-filmstrip-launcher__text">
            <strong>Page preview &amp; reorder</strong>
            <span>
              {pageForms.length} page{pageForms.length === 1 ? "" : "s"}
              {orderDirty ? " · unsaved order" : ""}
            </span>
          </span>
        </button>
      </div>
    );
  }

  return (
    <section
      id="doc-page-filmstrip-panel"
      className={panelClassName}
      aria-label="Page previews and order"
    >
      <div className="doc-page-filmstrip__toolbar">
        <div className="doc-page-filmstrip__toolbar-text">
          <h2 className="doc-page-filmstrip__title">Page preview &amp; reorder</h2>
          <p className="doc-page-filmstrip__hint">
            {canReorder
              ? "Click a page to jump. Drag by the handle or use the arrow buttons to reorder, then save."
              : "Click a page thumbnail to jump to that page in the document."}
          </p>
        </div>
        <div className="doc-page-filmstrip__toolbar-actions">
          {orderDirty ? (
            <>
              <span className="doc-page-filmstrip__unsaved">Unsaved order</span>
              <button
                type="button"
                className="swi-btn swi-btn--ghost doc-page-filmstrip__reset"
                disabled={disabled}
                onClick={onResetOrder}
              >
                Reset order
              </button>
            </>
          ) : (
            <span className="doc-page-filmstrip__saved">Order saved</span>
          )}
          <button
            type="button"
            className="swi-btn swi-btn--ghost doc-page-filmstrip__close"
            onClick={() => setPanelOpen(false)}
            aria-label="Close page preview panel"
          >
            Close
          </button>
        </div>
      </div>

      <div ref={scrollRef} className="doc-page-filmstrip__scroll">
        <ol
          ref={listRef}
          className="doc-page-filmstrip__list"
          onDragOver={onDragOverList}
          onDrop={onDropList}
        >
          {pageForms.map((pageForm, index) => {
            const key = pageKey(pageForm, index);
            const isDragging = dragIndex === index;
            const isActive = activeIndex === index;
            const preview = pagePreviewSnapshot(pageForm, index);

            return (
              <li
                key={key}
                className={`doc-page-filmstrip__item${isDragging ? " is-dragging-source" : ""}`}
              >
                {canReorder ? (
                  <div
                    className="doc-page-filmstrip__grip"
                    draggable
                    title="Drag to reorder"
                    aria-label={`Drag page ${index + 1} to reorder`}
                    onDragStart={onDragStart(index)}
                    onDragEnd={onDragEnd}
                  >
                    <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor" aria-hidden>
                      <circle cx="9" cy="6" r="1.75" />
                      <circle cx="15" cy="6" r="1.75" />
                      <circle cx="9" cy="12" r="1.75" />
                      <circle cx="15" cy="12" r="1.75" />
                      <circle cx="9" cy="18" r="1.75" />
                      <circle cx="15" cy="18" r="1.75" />
                    </svg>
                  </div>
                ) : null}

                <div
                  role="button"
                  tabIndex={disabled ? -1 : 0}
                  className="doc-page-filmstrip__select"
                  aria-disabled={disabled ? "true" : undefined}
                  onClick={() => !disabled && jumpToPage(index)}
                  onKeyDown={(e) => {
                    if (disabled) return;
                    if (e.key === "Enter" || e.key === " ") {
                      e.preventDefault();
                      jumpToPage(index);
                    }
                  }}
                  title={`Go to page ${index + 1}: ${preview.title}`}
                  aria-label={`Page ${index + 1}, ${preview.title}. Click to view.`}
                  aria-current={isActive ? "true" : undefined}
                >
                  <PageThumbnail
                    pageForm={pageForm}
                    pageIndex={index}
                    isDragging={isDragging}
                    isActive={isActive}
                  />
                  <span className="doc-page-filmstrip__caption">
                    Page {index + 1}
                  </span>
                  <span className="doc-page-filmstrip__caption-title">
                    {preview.title}
                  </span>
                </div>

                {canReorder ? (
                  <div className="doc-page-filmstrip__nudge">
                    <button
                      type="button"
                      className="doc-page-filmstrip__nudge-btn"
                      disabled={index === 0}
                      aria-label={`Move page ${index + 1} earlier`}
                      onClick={(e) => {
                        e.stopPropagation();
                        move(index, index - 1);
                      }}
                    >
                      ↑
                    </button>
                    <button
                      type="button"
                      className="doc-page-filmstrip__nudge-btn"
                      disabled={index === pageForms.length - 1}
                      aria-label={`Move page ${index + 1} later`}
                      onClick={(e) => {
                        e.stopPropagation();
                        move(index, index + 1);
                      }}
                    >
                      ↓
                    </button>
                  </div>
                ) : null}
              </li>
            );
          })}
        </ol>
      </div>
    </section>
  );
}
