import { LoaderCircle } from "lucide-react";
import { DownloadCloudIcon } from "../../icons/DownloadCloudIcon";
import { useState } from "react";
import { useI18n } from "../../../i18n";
import type { Attachment, Post } from "../../../types/post";
import { downloadAttachment } from "../utils/downloadFile";
import { fileIcon } from "../utils/fileIcon";
import { filenameWithExtension, splitFilename } from "../utils/filenameDisplay";
import { formatBytes } from "../utils/formatBytes";
import { formatDateTime } from "../utils/formatTime";
import { postDisplayText } from "../utils/postText";
import { CollapsibleText } from "../CollapsibleText";
import {
  mediaSaveKindFromAttachment,
  useSaveToAlbumGuide,
} from "../../SaveToAlbumGuide";
import { useToast } from "../../Toast";
import { FavoriteButton } from "../../../favorites/FavoriteButton";
import type { MessageBubbleVariant } from "../MessageBubble";

function AttachmentRow({ postId, att }: { postId: string; att: Attachment }) {
  const { t } = useI18n();
  const { showToast } = useToast();
  const { showSaveToAlbumGuide } = useSaveToAlbumGuide();
  const { Icon, color } = fileIcon({ mime: att.mime, filename: att.filename });
  const displayFilename = filenameWithExtension(att.filename, att.mime);
  const [isDownloading, setIsDownloading] = useState(false);
  const [previewFailed, setPreviewFailed] = useState(false);

  const handleDownload = async () => {
    if (isDownloading) return;
    setIsDownloading(true);
    try {
      await downloadAttachment(postId, att.id, displayFilename);
      const mediaKind = mediaSaveKindFromAttachment(att);
      if (mediaKind) showSaveToAlbumGuide(mediaKind);
    } catch {
      showToast(t("downloadFail"), "error");
    } finally {
      setIsDownloading(false);
    }
  };

  const isImage = att.kind === "image" || att.mime.startsWith("image/");
  const previewUrl =
    att.thumbnailUrl ?? att.posterUrl ?? (isImage ? att.url : undefined);

  return (
    <div className="group flex min-h-[64px] items-center gap-3">
      {previewUrl && !previewFailed ? (
        <img
          src={previewUrl}
          alt=""
          loading="lazy"
          decoding="async"
          onError={() => setPreviewFailed(true)}
          className="h-16 w-16 shrink-0 rounded-lg object-fill"
        />
      ) : (
        <div
          className="flex h-16 w-16 shrink-0 items-center justify-center rounded-lg"
          style={{ backgroundColor: color }}
          aria-hidden="true"
        >
          <Icon className="h-9 w-9 text-white" strokeWidth={2.1} />
        </div>
      )}
      <div className="min-w-0 flex-1">
        <div
          className="flex min-w-0 items-baseline text-[15px] font-medium leading-6 text-ark-gold group-hover:text-ark-gold2"
          title={displayFilename}
        >
          {(() => {
            const { base, ext } = splitFilename(displayFilename);
            const tailChars = Math.min(4, base.length);
            const head = base.slice(0, base.length - tailChars);
            const tail = base.slice(base.length - tailChars) + ext;
            return (
              <>
                <span className="min-w-0 truncate">{head}</span>
                <span className="shrink-0 whitespace-pre">{tail}</span>
              </>
            );
          })()}
        </div>
        <div className="text-[12px] font-medium leading-[19.2px] text-[#A8A9AE]">
          {isDownloading ? t("downloading") : formatBytes(att.sizeBytes)}
        </div>
      </div>
      <button
        type="button"
        onClick={handleDownload}
        disabled={isDownloading}
        className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-[#191921] text-white transition hover:bg-[#22232D] disabled:cursor-wait"
        aria-label={
          isDownloading ? t("downloading") : `Download ${att.filename}`
        }
        aria-busy={isDownloading}
      >
        {isDownloading ? (
          <LoaderCircle className="h-5 w-5 animate-spin" strokeWidth={2.3} />
        ) : (
          <DownloadCloudIcon className="h-6 w-6" />
        )}
      </button>
    </div>
  );
}

function LatestFileCard({ post }: { post: Post }) {
  const { t, lang } = useI18n();
  const { showToast } = useToast();
  const { showSaveToAlbumGuide } = useSaveToAlbumGuide();
  const [isDownloading, setIsDownloading] = useState(false);
  const att = post.attachments[0];
  const text = postDisplayText(post, lang);

  if (!att) return null;

  const { Icon, color } = fileIcon({ mime: att.mime, filename: att.filename });
  const displayFilename = filenameWithExtension(att.filename, att.mime);

  const handleDownload = async () => {
    if (isDownloading) return;
    setIsDownloading(true);
    try {
      await downloadAttachment(post.id, att.id, displayFilename);
      const mediaKind = mediaSaveKindFromAttachment(att);
      if (mediaKind) showSaveToAlbumGuide(mediaKind);
    } catch {
      showToast(t("downloadFail"), "error");
    } finally {
      setIsDownloading(false);
    }
  };

  return (
    <div className="flex h-[188px] flex-col gap-6 px-4 py-4">
      <div className="flex h-[52px] min-w-0 items-center gap-4">
        <div
          className="flex h-[52px] w-[52px] shrink-0 items-center justify-center rounded-full"
          style={{ backgroundColor: color }}
          aria-hidden="true"
        >
          <Icon className="h-8 w-8 text-white" strokeWidth={2.1} />
        </div>
        <div className="min-w-0 flex-1">
          <div
            className="flex min-w-0 items-baseline text-[15px] font-medium leading-6 text-ark-gold"
            title={displayFilename}
          >
            {(() => {
              const { base, ext } = splitFilename(displayFilename);
              const tailChars = Math.min(8, base.length);
              const head = base.slice(0, base.length - tailChars);
              const tail = base.slice(base.length - tailChars) + ext;
              return (
                <>
                  <span className="min-w-0 truncate">{head}</span>
                  <span className="shrink-0 whitespace-pre">{tail}</span>
                </>
              );
            })()}
          </div>
          <div className="text-[12px] font-medium leading-[19.2px] text-[#A8A9AE]">
            {isDownloading ? t("downloading") : formatBytes(att.sizeBytes)}
          </div>
        </div>
      </div>

      {text ? (
        <div className="message-stream-copyable-text line-clamp-2 min-h-[48px] select-text whitespace-pre-wrap break-words text-[15px] font-medium leading-6 text-white">
          {text}
        </div>
      ) : (
        <div className="min-h-[48px]" />
      )}

      <div className="mt-auto flex h-10 items-end justify-between gap-3">
        <time
          dateTime={post.publishedAt}
          className="text-[12px] font-medium leading-[19.2px] text-[#A8A9AE]"
        >
          {formatDateTime(post.publishedAt)}
        </time>
        <div className="flex shrink-0 items-center gap-2">
          <FavoriteButton resourceId={post.id} size="sm" />
          <button
            type="button"
            onClick={handleDownload}
            disabled={isDownloading}
            className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-[#191921] transition hover:bg-[#22232D] disabled:cursor-wait"
            aria-label={
              isDownloading ? t("downloading") : `Download ${att.filename}`
            }
            aria-busy={isDownloading}
          >
            {isDownloading ? (
              <LoaderCircle
                className="h-5 w-5 animate-spin text-[#A8A9AE]"
                strokeWidth={2.3}
              />
            ) : (
              <DownloadCloudIcon />
            )}
          </button>
        </div>
      </div>
    </div>
  );
}

export function FileDocBubble({
  post,
  variant = "default",
}: {
  post: Post;
  variant?: MessageBubbleVariant;
}) {
  const { lang } = useI18n();
  const text = postDisplayText(post, lang);

  if (variant === "latest") {
    return <LatestFileCard post={post} />;
  }

  return (
    <div className="flex flex-col gap-3">
      {post.attachments.map((att) => (
        <AttachmentRow key={att.id} postId={post.id} att={att} />
      ))}
      {text ? (
        <CollapsibleText className="message-stream-copyable-text select-text whitespace-pre-wrap break-words text-[15px] font-medium leading-6 text-neutral-100">
          {text}
        </CollapsibleText>
      ) : null}
    </div>
  );
}
