import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useRef,
  useState,
  type PropsWithChildren,
} from "react";
import { createPortal } from "react-dom";
import { ChevronLeft, ChevronRight, Download, X } from "lucide-react";
import { postNoBody } from "../../../api";
import type { Attachment } from "../../../types/post";
import { autolink } from "../utils/autolink";

type LightboxState = {
  images: Attachment[];
  index: number;
  caption?: string;
  postId?: string;
} | null;

type Ctx = {
  openLightbox: (
    images: Attachment[],
    startIndex?: number,
    caption?: string,
    postId?: string,
  ) => void;
  closeLightbox: () => void;
};

const LightboxContext = createContext<Ctx | null>(null);

export function useLightbox(): Ctx {
  const ctx = useContext(LightboxContext);
  if (!ctx)
    throw new Error("useLightbox must be used inside ImageLightboxProvider");
  return ctx;
}

export function ImageLightboxProvider({ children }: PropsWithChildren) {
  const [state, setState] = useState<LightboxState>(null);

  const openLightbox = useCallback(
    (
      images: Attachment[],
      startIndex = 0,
      caption?: string,
      postId?: string,
    ) => {
      if (!images.length) return;
      const i = Math.min(Math.max(0, startIndex), images.length - 1);
      setState({ images, index: i, caption, postId });
    },
    [],
  );

  const closeLightbox = useCallback(() => setState(null), []);

  return (
    <LightboxContext.Provider value={{ openLightbox, closeLightbox }}>
      {children}
      {state ? (
        <LightboxView
          images={state.images}
          startIndex={state.index}
          caption={state.caption}
          postId={state.postId}
          onClose={closeLightbox}
        />
      ) : null}
    </LightboxContext.Provider>
  );
}

function LightboxView({
  images,
  startIndex,
  caption: captionText,
  postId,
  onClose,
}: {
  images: Attachment[];
  startIndex: number;
  caption?: string;
  postId?: string;
  onClose: () => void;
}) {
  const [index, setIndex] = useState(startIndex);
  const touchStartX = useRef<number | null>(null);

  const goPrev = useCallback(
    () => setIndex((i) => (i - 1 + images.length) % images.length),
    [images.length],
  );
  const goNext = useCallback(
    () => setIndex((i) => (i + 1) % images.length),
    [images.length],
  );

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if (e.key === "Escape") onClose();
      if (e.key === "ArrowLeft") goPrev();
      if (e.key === "ArrowRight") goNext();
    };
    window.addEventListener("keydown", onKey);
    const prevOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", onKey);
      document.body.style.overflow = prevOverflow;
    };
  }, [goPrev, goNext, onClose]);

  const current = images[index];
  const caption = captionText?.trim();
  if (!current) return null;

  return createPortal(
    <div
      className="fixed inset-0 z-[100] flex items-center justify-center bg-black/95 backdrop-blur-sm"
      onClick={onClose}
      role="dialog"
      aria-modal="true"
    >
      <button
        type="button"
        onClick={(e) => {
          e.stopPropagation();
          onClose();
        }}
        className="absolute right-4 top-4 z-10 flex h-10 w-10 items-center justify-center rounded-full bg-white/10 text-white transition hover:bg-white/20"
        aria-label="Close"
      >
        <X className="h-5 w-5" />
      </button>

      <a
        href={current.url}
        download={current.filename}
        target="_blank"
        rel="noopener noreferrer"
        onClick={(e) => {
          e.stopPropagation();
          if (postId) {
            void postNoBody(
              `/api/posts/${postId}/attachments/${current.id}/download`,
            );
          }
        }}
        className="absolute right-16 top-4 z-10 flex h-10 w-10 items-center justify-center rounded-full bg-white/10 text-white transition hover:bg-white/20"
        aria-label="Download"
      >
        <Download className="h-5 w-5" />
      </a>

      {images.length > 1 ? (
        <>
          <button
            type="button"
            onClick={(e) => {
              e.stopPropagation();
              goPrev();
            }}
            className="absolute left-2 top-1/2 z-10 flex h-12 w-12 -translate-y-1/2 items-center justify-center rounded-full bg-white/10 text-white transition hover:bg-white/20 md:left-6"
            aria-label="Previous"
          >
            <ChevronLeft className="h-6 w-6" />
          </button>
          <button
            type="button"
            onClick={(e) => {
              e.stopPropagation();
              goNext();
            }}
            className="absolute right-2 top-1/2 z-10 flex h-12 w-12 -translate-y-1/2 items-center justify-center rounded-full bg-white/10 text-white transition hover:bg-white/20 md:right-6"
            aria-label="Next"
          >
            <ChevronRight className="h-6 w-6" />
          </button>
          <div className="absolute bottom-6 left-1/2 z-10 -translate-x-1/2 rounded-full bg-white/10 px-3 py-1 text-xs text-white">
            {index + 1} / {images.length}
          </div>
        </>
      ) : null}

      <div
        className="relative inline-block max-h-[92vh] max-w-[92vw]"
        onClick={(e) => e.stopPropagation()}
        onTouchStart={(e) => {
          touchStartX.current = e.touches[0].clientX;
        }}
        onTouchEnd={(e) => {
          if (touchStartX.current == null) return;
          const dx = e.changedTouches[0].clientX - touchStartX.current;
          if (Math.abs(dx) > 40) {
            if (dx > 0) goPrev();
            else goNext();
          }
          touchStartX.current = null;
        }}
      >
        <img
          src={current.url}
          alt={current.filename}
          className="max-h-[92vh] max-w-[92vw] object-contain select-none"
          draggable={false}
        />
        {caption ? (
          <div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/90 via-black/60 to-transparent px-4 pb-4 pt-12 text-sm leading-snug text-white sm:px-5 sm:pb-5">
            <div className="max-h-[32vh] overflow-y-auto whitespace-pre-wrap break-words">
              {autolink(caption)}
            </div>
          </div>
        ) : null}
      </div>
    </div>,
    document.body,
  );
}
