import { useCallback, useEffect } from 'react';
import { Dialog as DialogPrimitive } from 'radix-ui';
import {
  ChevronLeft,
  ChevronRight,
  Download,
  FileIcon,
  Loader2,
  Trash2,
  X,
} from 'lucide-react';
import { useDownloadUrl } from '@/hooks/use-download-url';
import { useObjectUrl } from '@/hooks/use-object-url';
import { Button } from '@/components/ui/button';
import { KeyHint } from '@/components/key-hint';
import { useSuspendPlayback } from '@/hooks/use-suspend-playback';
import { platform } from '@/lib/platform';

export interface AttachmentItem {
  id: string;
  filename: string;
  mimeType: string;
  sizeBytes?: number;
  source: { kind: 'remote'; objectId: string } | { kind: 'local'; file: File };
}

interface AttachmentLightboxProps {
  items: AttachmentItem[];
  openIndex: number | null;
  onOpenChange: (index: number | null) => void;
  /** When provided, enables the trash button + Backspace/Delete to remove. */
  onRemove?: (item: AttachmentItem) => void;
}

/**
 * Return `"lightbox"` for mime types that preview in-app, `"external"` otherwise.
 * Callers use this to decide whether to open the lightbox or hand off to the OS.
 */
export function getAttachmentHandler(
  mimeType: string,
): 'lightbox' | 'external' {
  if (mimeType.startsWith('image/') || mimeType.startsWith('video/')) {
    return 'lightbox';
  }
  return 'external';
}

function formatSize(bytes?: number): string | null {
  if (bytes == null) return null;
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

export function AttachmentLightbox({
  items,
  openIndex,
  onOpenChange,
  onRemove,
}: AttachmentLightboxProps) {
  const current =
    openIndex !== null && openIndex >= 0 && openIndex < items.length
      ? items[openIndex]
      : null;
  const isOpen = current !== null;
  const hasMultiple = items.length > 1;
  const positionIndicator = openIndex !== null ? openIndex + 1 : null;

  // Remote items resolve through the signed-URL cache; disabled when not remote.
  const remoteObjectId =
    current?.source.kind === 'remote' ? current.source.objectId : undefined;
  const { data: remoteUrl, isLoading: isRemoteLoading } =
    useDownloadUrl(remoteObjectId);

  // Local items resolve to a blob URL; remote items use the signed-URL cache.
  const localFile =
    current?.source.kind === 'local' ? current.source.file : null;
  const localUrl = useObjectUrl(localFile);

  const url =
    current?.source.kind === 'remote' ? (remoteUrl ?? null) : localUrl;

  const canDownload = current?.source.kind === 'remote' && !!url;

  const goTo = useCallback(
    (delta: number) => {
      if (openIndex === null || items.length === 0) return;
      const next = (openIndex + delta + items.length) % items.length;
      onOpenChange(next);
    },
    [openIndex, items.length, onOpenChange],
  );

  const handleDownload = useCallback(() => {
    if (!current || !url || current.source.kind !== 'remote') return;
    platform.attachment.download(url, current.filename);
  }, [current, url]);

  const handleRemove = useCallback(() => {
    if (!current || !onRemove) return;
    const wasLast = items.length <= 1;
    const wasAtEnd = openIndex === items.length - 1;
    onRemove(current);
    if (wasLast) {
      onOpenChange(null);
    } else if (wasAtEnd) {
      onOpenChange(items.length - 2);
    }
    // Otherwise openIndex stays — the next item shifts into its place.
  }, [current, onRemove, items.length, openIndex, onOpenChange]);

  useSuspendPlayback(isOpen, 'attachment-lightbox');

  // Keyboard handling — only listens while open. Registered in the capture
  // phase with stopImmediatePropagation so we consume keys (arrows, D, ⌫)
  // before global listeners like stream-view's particle-navigation.
  useEffect(() => {
    if (!isOpen) return;
    const handle = (e: KeyboardEvent) => {
      const target = e.target as HTMLElement | null;
      if (
        target &&
        (target.tagName === 'INPUT' ||
          target.tagName === 'TEXTAREA' ||
          target.isContentEditable)
      ) {
        return;
      }
      const consume = () => {
        e.preventDefault();
        e.stopImmediatePropagation();
      };
      if (e.key === 'Escape') {
        consume();
        onOpenChange(null);
      } else if (e.key === 'ArrowLeft' && hasMultiple) {
        consume();
        goTo(-1);
      } else if (e.key === 'ArrowRight' && hasMultiple) {
        consume();
        goTo(1);
      } else if ((e.key === 'd' || e.key === 'D') && canDownload) {
        consume();
        handleDownload();
      } else if ((e.key === 'Backspace' || e.key === 'Delete') && onRemove) {
        consume();
        handleRemove();
      }
    };
    window.addEventListener('keydown', handle, true);
    return () => window.removeEventListener('keydown', handle, true);
  }, [
    isOpen,
    onOpenChange,
    onRemove,
    hasMultiple,
    canDownload,
    goTo,
    handleDownload,
    handleRemove,
  ]);

  const isImage = current?.mimeType.startsWith('image/');
  const isVideo = current?.mimeType.startsWith('video/');
  const sizeLabel = formatSize(current?.sizeBytes);

  return (
    <DialogPrimitive.Root
      open={isOpen}
      onOpenChange={(open) => {
        if (!open) onOpenChange(null);
      }}
    >
      <DialogPrimitive.Portal>
        <DialogPrimitive.Overlay className="data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 z-50 bg-black/90 backdrop-blur-sm duration-100" />
        <DialogPrimitive.Content
          aria-describedby={undefined}
          className="data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 fixed inset-0 z-50 flex items-center justify-center p-16 outline-none duration-100"
        >
          {current && (
            <>
              <DialogPrimitive.Title className="sr-only">
                {current.filename}
              </DialogPrimitive.Title>

              {/* Top-left: filename chip */}
              <div className="absolute left-4 top-4 flex items-center gap-2 rounded-2xl border border-white/10 bg-white/5 px-3 py-1.5 backdrop-blur-xl">
                <span className="max-w-[40vw] truncate text-sm text-white/80">
                  {current.filename}
                </span>
                {sizeLabel && (
                  <span className="text-xs text-white/40">{sizeLabel}</span>
                )}
                {hasMultiple && (
                  <span className="border-l border-white/10 pl-2 text-xs text-white/40">
                    {positionIndicator} / {items.length}
                  </span>
                )}
              </div>

              {/* Top-right: actions */}
              <div className="absolute right-4 top-4 flex items-center gap-1 no-drag">
                {canDownload && (
                  <Button
                    variant="ghost"
                    size="icon-sm"
                    onClick={handleDownload}
                    className="text-white/70 hover:bg-white/10 hover:text-white"
                    title="Download"
                  >
                    <Download />
                  </Button>
                )}
                {onRemove && (
                  <Button
                    variant="ghost"
                    size="icon-sm"
                    onClick={handleRemove}
                    className="text-white/70 hover:bg-white/10 hover:text-white"
                    title="Remove"
                  >
                    <Trash2 />
                  </Button>
                )}
                <DialogPrimitive.Close asChild>
                  <Button
                    variant="ghost"
                    size="icon-sm"
                    className="text-white/70 hover:bg-white/10 hover:text-white"
                    title="Close"
                  >
                    <X />
                  </Button>
                </DialogPrimitive.Close>
              </div>

              {/* Side navigation */}
              {hasMultiple && (
                <>
                  <Button
                    variant="ghost"
                    size="icon"
                    onClick={() => goTo(-1)}
                    className="absolute left-4 top-1/2 -translate-y-1/2 text-white/70 hover:bg-white/10 hover:text-white"
                    aria-label="Previous"
                  >
                    <ChevronLeft />
                  </Button>
                  <Button
                    variant="ghost"
                    size="icon"
                    onClick={() => goTo(1)}
                    className="absolute right-4 top-1/2 -translate-y-1/2 text-white/70 hover:bg-white/10 hover:text-white"
                    aria-label="Next"
                  >
                    <ChevronRight />
                  </Button>
                </>
              )}

              {/* Media body */}
              <div className="flex max-h-full max-w-full items-center justify-center">
                {!url && isRemoteLoading && (
                  <Loader2 className="size-8 animate-spin text-white/50" />
                )}
                {url && isImage && (
                  <img
                    key={current.id}
                    src={url}
                    alt={current.filename}
                    onError={() => onOpenChange(null)}
                    className="max-h-[85vh] max-w-[85vw] rounded-lg object-contain shadow-2xl"
                  />
                )}
                {url && isVideo && (
                  <video
                    key={current.id}
                    src={url}
                    controls
                    autoPlay
                    className="max-h-[85vh] max-w-[85vw] rounded-lg shadow-2xl"
                  />
                )}
                {url && !isImage && !isVideo && (
                  <div className="flex flex-col items-center gap-3 rounded-2xl border border-white/10 bg-white/5 px-8 py-6 backdrop-blur-xl">
                    <FileIcon className="size-12 text-white/50" />
                    <span className="text-sm text-white/80">
                      {current.filename}
                    </span>
                  </div>
                )}
              </div>

              {/* Footer kbd hints */}
              <div className="absolute bottom-4 left-1/2 flex -translate-x-1/2 items-center gap-4 text-xs text-white/50">
                {hasMultiple && (
                  <span className="flex items-center gap-1.5">
                    <KeyHint
                      keys="←"
                      onClick={() => goTo(-1)}
                      title="Previous (or press ←)"
                      aria-label="Previous attachment"
                    />
                    <KeyHint
                      keys="→"
                      onClick={() => goTo(1)}
                      title="Next (or press →)"
                      aria-label="Next attachment"
                    />
                    navigate
                  </span>
                )}
                {canDownload && (
                  <KeyHint
                    keys="D"
                    onClick={handleDownload}
                    title="Download (or press D)"
                  >
                    download
                  </KeyHint>
                )}
                {onRemove && (
                  <KeyHint
                    keys="⌫"
                    onClick={handleRemove}
                    title="Remove (or press Backspace)"
                  >
                    remove
                  </KeyHint>
                )}
                <KeyHint
                  keys="Esc"
                  onClick={() => onOpenChange(null)}
                  title="Close (or press Esc)"
                >
                  close
                </KeyHint>
              </div>
            </>
          )}
        </DialogPrimitive.Content>
      </DialogPrimitive.Portal>
    </DialogPrimitive.Root>
  );
}
