import { LoaderCircle, X } from "lucide-react";
import { DownloadCloudIcon } from "../../icons/DownloadCloudIcon";
import { useEffect, useState } from "react";
import { createPortal } from "react-dom";
import { useI18n } from "../../../i18n";
import type { Attachment, Post } from "../../../types/post";
import { AttachmentDownloadPill } from "../AttachmentDownloadPill";
import { useLightbox } from "../overlays/ImageLightbox";
import { autolink } from "../utils/autolink";
import { downloadAttachment } from "../utils/downloadFile";
import { formatBytes } from "../utils/formatBytes";
import { postDisplayText } from "../utils/postText";
import { useToast } from "../../Toast";

const MAX_VISIBLE = 4;

function albumGridClass(count: number) {
  const height = "h-[230px] min-[440px]:h-[250px] md:h-[300px] lg:h-[340px]";
  if (count === 2) return `${height} grid grid-cols-1 grid-rows-2`;
  return `${height} grid grid-cols-2 grid-rows-2`;
}

function albumItemClass(index: number, count: number) {
  if (count === 3 && index === 0) return "row-span-2";
  return "";
}

function ImageListDownloadButton({
  postId,
  attachment,
}: {
  postId: string;
  attachment: Attachment;
}) {
  const { t } = useI18n();
  const { showToast } = useToast();
  const [isDownloading, setIsDownloading] = useState(false);

  const handleDownload = async () => {
    if (isDownloading) return;
    setIsDownloading(true);
    try {
      await downloadAttachment(postId, attachment.id, attachment.filename);
      showToast(t("downloadOk"));
    } catch {
      showToast(t("downloadFail"), "error");
    } finally {
      setIsDownloading(false);
    }
  };

  return (
    <button
      type="button"
      onClick={(e) => {
        e.stopPropagation();
        handleDownload();
      }}
      disabled={isDownloading}
      className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-white/10 text-white transition hover:bg-white/20 disabled:cursor-wait"
      aria-label={
        isDownloading ? t("downloading") : `Download ${attachment.filename}`
      }
      aria-busy={isDownloading}
    >
      {isDownloading ? (
        <LoaderCircle className="h-4 w-4 animate-spin" strokeWidth={2.3} />
      ) : (
        <DownloadCloudIcon className="h-4 w-4" />
      )}
    </button>
  );
}

function ImageListDialog({
  postId,
  images,
  onClose,
  onPick,
}: {
  postId: string;
  images: Attachment[];
  onClose: () => void;
  onPick: (index: number) => void;
}) {
  useEffect(() => {
    const onKey = (event: KeyboardEvent) => {
      if (event.key === "Escape") onClose();
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  return createPortal(
    <div
      className="fixed inset-0 z-[100] flex items-center justify-center bg-black/75 px-4 backdrop-blur-sm"
      onClick={onClose}
      role="dialog"
      aria-modal="true"
      aria-label="Image list"
    >
      <div
        className="w-full max-w-md overflow-hidden rounded-2xl border border-ark-line bg-ark-panel shadow-2xl"
        onClick={(e) => e.stopPropagation()}
      >
        <div className="flex items-center justify-between border-b border-ark-line px-4 py-3">
          <div className="text-sm font-semibold text-neutral-100">选择图片</div>
          <button
            type="button"
            onClick={onClose}
            className="flex h-8 w-8 items-center justify-center rounded-full bg-white/10 text-white transition hover:bg-white/20"
            aria-label="Close"
          >
            <X className="h-4 w-4" />
          </button>
        </div>
        <div className="max-h-[70vh] overflow-y-auto p-2 [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
          {images.map((image, index) => (
            <div
              key={image.id}
              className="flex w-full items-center gap-3 rounded-xl p-2 text-left transition hover:bg-white/5"
            >
              <button
                type="button"
                onClick={() => onPick(index)}
                className="flex min-w-0 flex-1 items-center gap-3 text-left"
              >
                <div className="h-16 w-16 shrink-0 overflow-hidden rounded-lg bg-black">
                  <img
                    src={image.thumbnailUrl ?? image.url}
                    alt=""
                    className="h-full w-full object-cover"
                  />
                </div>
                <div className="min-w-0 flex-1">
                  <div className="truncate text-sm font-medium text-neutral-100">
                    图片 {index + 1}
                  </div>
                  <div className="mt-1 truncate text-xs text-neutral-400">
                    {formatBytes(image.sizeBytes)}
                  </div>
                </div>
              </button>
              <ImageListDownloadButton postId={postId} attachment={image} />
            </div>
          ))}
        </div>
      </div>
    </div>,
    document.body,
  );
}

export function AlbumBubble({ post }: { post: Post }) {
  const { openLightbox } = useLightbox();
  const { lang } = useI18n();
  const [listOpen, setListOpen] = useState(false);
  const images = post.attachments;
  const text = postDisplayText(post, lang);
  const visible = images.slice(0, MAX_VISIBLE);
  const extra = images.length - MAX_VISIBLE;
  const layoutCount = Math.min(images.length, MAX_VISIBLE);

  return (
    <div className="flex flex-col">
      <div className={`${albumGridClass(layoutCount)} gap-px overflow-hidden`}>
        {visible.map((att, i) => {
          const isLastSlot = i === MAX_VISIBLE - 1 && extra > 0;
          return (
            <div
              key={att.id}
              className={`relative h-full w-full overflow-hidden ${albumItemClass(
                i,
                layoutCount,
              )}`}
            >
              <button
                type="button"
                onClick={() => {
                  if (isLastSlot) setListOpen(true);
                  else openLightbox(images, i, text, post.id);
                }}
                className="block h-full w-full"
                aria-label={isLastSlot ? "Open image list" : att.filename}
              >
                <img
                  src={att.thumbnailUrl ?? att.url}
                  alt={att.filename}
                  loading="lazy"
                  className="h-full w-full object-cover"
                />
                {isLastSlot ? (
                  <div className="absolute inset-0 flex items-center justify-center bg-black/55 text-4xl font-bold text-white">
                    +{extra}
                  </div>
                ) : null}
              </button>
              {!isLastSlot ? (
                <AttachmentDownloadPill postId={post.id} attachment={att} />
              ) : null}
            </div>
          );
        })}
      </div>
      {text ? (
        <div className="message-stream-copyable-text select-text whitespace-pre-wrap break-words px-4 pt-3 text-[14px] leading-6 text-neutral-100">
          {autolink(text)}
        </div>
      ) : null}
      {listOpen ? (
        <ImageListDialog
          postId={post.id}
          images={images}
          onClose={() => setListOpen(false)}
          onPick={(index) => {
            setListOpen(false);
            openLightbox(images, index, text, post.id);
          }}
        />
      ) : null}
    </div>
  );
}
