import { useEffect } from 'react';
import type { JSX } from 'react';
import { ArrowLeftIcon, ArrowRightIcon } from '../ui/icons';
import { useAssetNavigator } from '../hooks/useAssetNavigator';
import { preventAll } from './events';

type Identifier = string | number;

interface DocumentLike {
  id?: Identifier;
  title?: string;
  [key: string]: unknown;
}

interface AssetLike {
  id?: Identifier;
  cardinality?: number;
  url?: string | null;
  metadata?: Record<string, unknown> | null;
  objects?: Array<Record<string, unknown>>;
  [key: string]: unknown;
}

type EnsureAssetUrl = (
  documentId: Identifier,
  asset: AssetLike,
  options?: { start?: number; limit?: number; [key: string]: unknown },
) => Promise<unknown>;

type GetDocumentAsset = (document: DocumentLike | null | undefined, assetType: string) => AssetLike | null | undefined;

interface NavigatorSnapshot {
  url: string | null;
  alt?: string;
  canGoPrev: boolean;
  canGoNext: boolean;
  goPrev?: () => void;
  goNext?: () => void;
  ordinal: number;
  width: number | null;
  height: number | null;
}

interface DesktopPreviewCardProps {
  doc: DocumentLike | null;
  title?: string;
  ensureAssetUrl?: EnsureAssetUrl | null;
  getDocumentAsset: GetDocumentAsset;
  prefetch?: number;
  onNavigatorSnapshot?: (docId: Identifier, snapshot: NavigatorSnapshot | null) => void;
  shouldLoad?: boolean;
}

const DesktopPreviewCard = ({
  doc,
  title,
  ensureAssetUrl,
  getDocumentAsset,
  prefetch = 3,
  onNavigatorSnapshot,
  shouldLoad = true,
}: DesktopPreviewCardProps): JSX.Element => {
  const navigator = useAssetNavigator({
    document: doc,
    assetType: 'preview',
    ensureAssetUrl: shouldLoad ? ensureAssetUrl : null,
    getAsset: getDocumentAsset,
    prefetch,
  });

  const { currentUrl, cardinality, canGoPrev, canGoNext, currentMetadata, ordinal } = navigator;
  const docId = doc?.id ?? null;

  const metadataWidth = Number((currentMetadata as { width?: number } | null)?.width);
  const metadataHeight = Number((currentMetadata as { height?: number } | null)?.height);

  useEffect(() => {
    if (!onNavigatorSnapshot || !docId) {
      return undefined;
    }
    const snapshot = {
      url: currentUrl || null,
      alt: title,
      canGoPrev,
      canGoNext,
      goPrev: navigator.goPrev,
      goNext: navigator.goNext,
      ordinal,
      width: Number.isFinite(metadataWidth) && metadataWidth > 0 ? metadataWidth : null,
      height: Number.isFinite(metadataHeight) && metadataHeight > 0 ? metadataHeight : null,
    };
    onNavigatorSnapshot(docId, snapshot);
    return () => onNavigatorSnapshot(docId, null);
  }, [
    docId,
    currentUrl,
    title,
    canGoPrev,
    canGoNext,
    ordinal,
    metadataWidth,
    metadataHeight,
    navigator.goPrev,
    navigator.goNext,
    onNavigatorSnapshot,
  ]);

  const hasPreview = Boolean(currentUrl);
  const cardClasses = ['desk-item__card'];
  if (!hasPreview) cardClasses.push('desk-item__card--empty');
  const showNav = hasPreview && (cardinality > 1 || canGoPrev || canGoNext);

  return (
    <div
      className={cardClasses.join(' ')}
      onDragStart={(event) => {
        if (event instanceof DragEvent) {
          event.preventDefault();
        }
      }}
    >
      {hasPreview ? (
        <img
          src={currentUrl}
          alt={title}
          draggable={false}
          onDragStart={(event) => event.preventDefault()}
        />
      ) : (
        <div className="desk-item__empty">
          <div className="desk-item__placeholder">DOC</div>
          <div className="desk-item__title" title={title}>
            {title}
          </div>
        </div>
      )}
      {showNav ? (
        <div className="desk-card__nav">
          <button
            type="button"
            className="desk-card__nav-button"
            onClick={(event) => {
              preventAll(event);
              navigator.goPrev();
            }}
            onPointerDown={(event) => {
              preventAll(event);
            }}
            onPointerUp={(event) => {
              preventAll(event);
            }}
            onMouseDown={(event) => {
              preventAll(event);
            }}
            onMouseUp={(event) => {
              preventAll(event);
            }}
            disabled={!canGoPrev}
            aria-label="Previous preview"
          >
            <ArrowLeftIcon />
          </button>
          <button
            type="button"
            className="desk-card__nav-button"
            onClick={(event) => {
              preventAll(event);
              navigator.goNext();
            }}
            onPointerDown={(event) => {
              preventAll(event);
            }}
            onPointerUp={(event) => {
              preventAll(event);
            }}
            onMouseDown={(event) => {
              preventAll(event);
            }}
            onMouseUp={(event) => {
              preventAll(event);
            }}
            disabled={!canGoNext}
            aria-label="Next preview"
          >
            <ArrowRightIcon />
          </button>
        </div>
      ) : null}
    </div>
  );
};

export default DesktopPreviewCard;
