import {
  isSupportAttachmentImage,
  type SupportAttachmentDto,
} from "@edr/types";
import { Box, Group, Image, Loader, Paper, Stack, Text } from "@mantine/core";
import { FileText, ImageOff } from "lucide-react";

import { useAttachmentObjectUrl } from "./useAttachmentObjectUrl";

/** Human-readable size — kept coarse; nobody needs bytes in a chat bubble. */
export function formatBytes(bytes: number): string {
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

/** Cap the bubble: a tall screenshot would push the conversation off-screen. */
const THUMB = { maxHeight: 220, maxWidth: 260 } as const;

/**
 * One image attachment. Its own component because the bytes are fetched through
 * the authenticated client (see {@link useAttachmentObjectUrl}) and a hook can't
 * be called from inside a `.map()`.
 */
function ImageAttachment({
  a,
  onView,
}: {
  a: SupportAttachmentDto;
  onView: (a: SupportAttachmentDto, src: string) => void;
}) {
  const { src, failed } = useAttachmentObjectUrl(a.url);

  if (failed) {
    return (
      <Group gap={6} c="dimmed">
        <ImageOff size={14} />
        <Text size="xs">Couldn't load {a.name}</Text>
      </Group>
    );
  }

  if (!src) {
    return (
      <Box
        style={{
          width: THUMB.maxWidth,
          height: 140,
          display: "grid",
          placeItems: "center",
          background: "var(--mantine-color-gray-1)",
          borderRadius: 8,
        }}
      >
        <Loader size="xs" color="edr-green" />
      </Box>
    );
  }

  return (
    <Box
      onClick={() => onView(a, src)}
      style={{ cursor: "zoom-in", borderRadius: 8, overflow: "hidden" }}
    >
      <Image src={src} alt={a.name} radius="md" fit="cover" style={THUMB} />
    </Box>
  );
}

/**
 * Attachments inside a message bubble: images as thumbnails, everything else as
 * a labelled file row. Non-images are not fetched until opened — pulling every
 * document in a thread just to draw a filename would be wasteful.
 */
export function MessageAttachments({
  attachments,
  mine,
  onView,
  onOpenFile,
}: {
  attachments: SupportAttachmentDto[];
  mine: boolean;
  onView: (a: SupportAttachmentDto, src: string) => void;
  onOpenFile: (a: SupportAttachmentDto) => void;
}) {
  if (attachments.length === 0) return null;

  return (
    <Stack gap={6} mt={6}>
      {attachments.map((a) =>
        isSupportAttachmentImage(a.mimeType) ? (
          <ImageAttachment key={a.id} a={a} onView={onView} />
        ) : (
          <Paper
            key={a.id}
            onClick={() => onOpenFile(a)}
            px="sm"
            py={6}
            radius="md"
            style={{
              cursor: "pointer",
              background: mine ? "rgba(255,255,255,0.16)" : "white",
              border: mine ? "none" : "1px solid var(--mantine-color-gray-3)",
            }}
          >
            <Group gap={8} wrap="nowrap">
              <FileText size={16} style={{ flexShrink: 0 }} />
              <Box style={{ minWidth: 0 }}>
                <Text size="xs" fw={600} truncate>
                  {a.name}
                </Text>
                <Text size="10px" opacity={0.75}>
                  {formatBytes(a.size)}
                </Text>
              </Box>
            </Group>
          </Paper>
        ),
      )}
    </Stack>
  );
}
