'use client';

import { useEffect, useMemo, useRef, useState } from 'react';
import { useDrag, useDrop } from 'react-dnd';
import type { DocumentListDocument } from '@/types/documents';
import { PDFIcon, EPUBIcon, FileIcon } from '@/components/icons/Icons';
import { DocumentPreview } from '@/components/doclist/DocumentPreview';
import { formatDocumentSize } from '@/components/doclist/formatSize';
import { Button, ButtonLink } from '@/components/ui';
import { useDocumentSelection } from '../dnd/DocumentSelectionContext';
import { DND_DOCUMENT, documentIdentityKey, type DocumentDragItem } from '../dnd/dndTypes';

interface GalleryViewProps {
  documents: DocumentListDocument[];
  folderNameById?: Record<string, string>;
  onDeleteDoc: (doc: DocumentListDocument) => void;
  onMergeIntoFolder: (sources: DocumentListDocument[], target: DocumentListDocument) => void;
}

function formatDateTime(value: number | undefined): string {
  if (!value || !Number.isFinite(value) || value <= 0) return 'Never';
  return new Date(value).toLocaleString(undefined, {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
    hour: 'numeric',
    minute: '2-digit',
  });
}

function KindIcon({ doc, className }: { doc: DocumentListDocument; className?: string }) {
  if (doc.type === 'pdf') return <PDFIcon className={className ?? 'w-4 h-4 text-danger'} />;
  if (doc.type === 'epub') return <EPUBIcon className={className ?? 'w-4 h-4 text-accent'} />;
  return <FileIcon className={className ?? 'w-4 h-4 text-soft'} />;
}

function GalleryThumb({
  doc,
  active,
  onClick,
  onMergeIntoFolder,
}: {
  doc: DocumentListDocument;
  active: boolean;
  onClick: () => void;
  onMergeIntoFolder: (sources: DocumentListDocument[], target: DocumentListDocument) => void;
}) {
  const selection = useDocumentSelection();
  const isSelected = selection.isSelected(doc);
  const isInFolder = Boolean(doc.folderId);
  const didDragRef = useRef(false);

  const [{ isDragging }, dragRef] = useDrag<DocumentDragItem, void, { isDragging: boolean }>(() => ({
    type: DND_DOCUMENT,
    item: () => {
      const sel = selection.getSelectedDocs();
      const dragging = isSelected && sel.length > 1 ? sel : [doc];
      if (!isSelected) selection.replace([doc]);
      return {
        items: dragging.map(({ id, type }) => ({ id, type })),
        docs: dragging,
        fromFolderId: doc.folderId,
      };
    },
    // A mouse drag ending on the same thumb is followed by a click. Flag the drag
    // so the click handler can ignore it; clear on the next macrotask in case the
    // drag ended elsewhere (no click fires).
    end: () => {
      didDragRef.current = true;
      setTimeout(() => { didDragRef.current = false; }, 0);
    },
    collect: (m) => ({ isDragging: m.isDragging() }),
  }), [doc, isSelected, selection]);

  const [{ isOver, canDrop }, dropRef] = useDrop<DocumentDragItem, void, { isOver: boolean; canDrop: boolean }>(() => ({
    accept: DND_DOCUMENT,
    canDrop: (item) => !isInFolder && !item.items.some((it) => documentIdentityKey(it) === documentIdentityKey(doc)),
    drop: (item) => onMergeIntoFolder(item.docs, doc),
    collect: (m) => ({ isOver: m.isOver({ shallow: true }), canDrop: m.canDrop() }),
  }), [doc, isInFolder, onMergeIntoFolder]);

  const setRefs = (node: HTMLDivElement | null) => {
    dragRef(node);
    dropRef(node);
  };

  return (
    <div
      ref={setRefs}
      data-doc-tile
      onClick={() => {
        if (didDragRef.current) {
          didDragRef.current = false;
          return;
        }
        onClick();
      }}
      aria-current={active ? 'true' : undefined}
      className={
        'group relative w-[98px] sm:w-[110px] shrink-0 cursor-pointer rounded-lg overflow-hidden border bg-surface snap-start transition duration-base ease-standard ' +
        // iOS: suppress the long-press link preview/callout and selection magnifier so the
        // long-press is handed to the touch DnD backend instead of the native preview.
        'select-none [-webkit-touch-callout:none] ' +
        (active
          ? 'border-accent-line shadow-elev-2 -translate-y-px'
          : 'border-line hover:border-accent-line hover:-translate-y-px hover:shadow-elev-2') +
        (isOver && canDrop ? ' border-accent-line' : '') +
        (isDragging ? ' opacity-50' : '')
      }
      title={doc.name}
    >
      <div className="aspect-[3/4] bg-surface">
        <DocumentPreview doc={doc} />
      </div>
      <div
        className={
          'px-2 py-1.5 flex items-center gap-1.5 border-t transition-colors duration-base ' +
          (active ? 'bg-surface-sunken border-accent-line' : 'bg-surface border-line')
        }
      >
        <KindIcon
          doc={doc}
          className={
            'w-3 h-3 shrink-0 transition-colors duration-base ' +
            (active ? 'text-accent' : 'text-soft')
          }
        />
        <span
          className={
            'truncate text-[10px] leading-none transition-colors duration-base ' +
            (active ? 'text-accent font-medium' : 'text-foreground')
          }
        >
          {doc.name}
        </span>
      </div>
    </div>
  );
}

export function GalleryView({
  documents,
  folderNameById,
  onDeleteDoc,
  onMergeIntoFolder,
}: GalleryViewProps) {
  const { setVisibleOrder } = useDocumentSelection();
  const railRef = useRef<HTMLDivElement | null>(null);
  const [activeIdx, setActiveIdx] = useState(0);
  const activeDoc = useMemo(() => documents[activeIdx], [documents, activeIdx]);
  const openHref = activeDoc ? `/${activeDoc.type}/${encodeURIComponent(activeDoc.id)}` : null;

  useEffect(() => {
    setVisibleOrder(documents);
  }, [documents, setVisibleOrder]);

  useEffect(() => {
    if (activeIdx >= documents.length) {
      setActiveIdx(Math.max(0, documents.length - 1));
    }
  }, [documents.length, activeIdx]);

  useEffect(() => {
    const rail = railRef.current;
    if (!rail) return;
    rail.scrollLeft = 0;
  }, [documents.length]);

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if (documents.length === 0) return;
      const target = e.target as HTMLElement;
      if (target?.closest('input, textarea, [contenteditable]')) return;
      if (e.key === 'ArrowRight') {
        setActiveIdx((i) => Math.min(documents.length - 1, i + 1));
      } else if (e.key === 'ArrowLeft') {
        setActiveIdx((i) => Math.max(0, i - 1));
      } else if (e.key === 'Delete' || e.key === 'Backspace') {
        const doc = documents[activeIdx];
        if (doc) {
          e.preventDefault();
          onDeleteDoc(doc);
        }
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [documents, activeIdx, onDeleteDoc]);

  return (
    <div className="flex-1 min-h-0 flex flex-col">
      <div className="flex-1 min-h-0 overflow-y-auto bg-surface-sunken">
        <div className="min-h-full flex items-center justify-center p-3 sm:p-6">
        {activeDoc ? (
          <div className="w-full max-w-[920px] flex flex-col md:flex-row items-center md:items-start justify-center gap-4 md:gap-6">
            <div className="flex flex-col items-center gap-3 w-[180px] sm:w-[260px] md:w-[320px] shrink-0">
              <div className="w-full aspect-[3/4] rounded-lg overflow-hidden border border-line shadow-elev-2">
                <DocumentPreview doc={activeDoc} />
              </div>
              <div className="text-center">
                <h2 className="text-[14px] font-semibold text-foreground truncate max-w-[320px]">
                  {activeDoc.name}
                </h2>
                <p className="text-[11px] text-soft">
                  {activeDoc.type.toUpperCase()} • {formatDocumentSize(activeDoc.size)}
                </p>
              </div>
              <div className="flex gap-2">
                <ButtonLink href={openHref || '/app'} prefetch={false} variant="primary" size="sm">
                  Open
                </ButtonLink>
                <Button
                  type="button"
                  onClick={() => onDeleteDoc(activeDoc)}
                  variant="secondary"
                  size="sm"
                >
                  Delete
                </Button>
              </div>
            </div>
            <dl className="w-full max-w-[280px] sm:max-w-[360px] md:max-w-[340px] grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 rounded-md border border-line bg-surface px-3 py-2 text-[11px] md:self-center">
              <dt className="text-soft">Type</dt>
              <dd className="text-foreground text-right uppercase tracking-wide">{activeDoc.type}</dd>
              <dt className="text-soft">Size</dt>
              <dd className="text-foreground text-right tabular-nums">{formatDocumentSize(activeDoc.size)}</dd>
              <dt className="text-soft">Last opened</dt>
              <dd className="text-foreground text-right">{formatDateTime(activeDoc.recentlyOpenedAt)}</dd>
              <dt className="text-soft">Last modified</dt>
              <dd className="text-foreground text-right">{formatDateTime(activeDoc.lastModified)}</dd>
              {activeDoc.folderId && (
                <>
                  <dt className="text-soft">Folder</dt>
                  <dd className="text-foreground text-right truncate" title={folderNameById?.[activeDoc.folderId] ?? activeDoc.folderId}>
                    {folderNameById?.[activeDoc.folderId] ?? activeDoc.folderId}
                  </dd>
                </>
              )}
            </dl>
          </div>
        ) : (
          <p className="text-[12px] text-soft">No documents to show</p>
        )}
        </div>
      </div>

      <div className="shrink-0 border-t border-line-soft bg-gradient-to-b from-surface to-surface-sunken">
        <div
          ref={railRef}
          className="flex gap-2.5 overflow-x-auto pl-4 pr-3 pt-2.5 pb-1.5 snap-x snap-proximity scroll-pl-4 sm:scroll-pl-5 scroll-pr-3 sm:scroll-pr-4"
        >
          {documents.map((doc, i) => (
            <GalleryThumb
              key={`${doc.type}-${doc.id}`}
              doc={doc}
              active={i === activeIdx}
              onClick={() => setActiveIdx(i)}
              onMergeIntoFolder={onMergeIntoFolder}
            />
          ))}
        </div>
      </div>
    </div>
  );
}
