"use client";

import {
	AttachmentPrimitive,
	ComposerPrimitive,
	MessagePrimitive,
	useAssistantApi,
	useAssistantState,
} from "@assistant-ui/react";
import { FileText, Loader2, PlusIcon, XIcon } from "lucide-react";
import Image from "next/image";
import { type FC, type PropsWithChildren, useEffect, useState } from "react";
import { useShallow } from "zustand/shallow";
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Dialog, DialogContent, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";

const useFileSrc = (file: File | undefined) => {
	const [src, setSrc] = useState<string | undefined>(undefined);

	useEffect(() => {
		if (!file) {
			setSrc(undefined);
			return;
		}

		const objectUrl = URL.createObjectURL(file);
		setSrc(objectUrl);

		return () => {
			URL.revokeObjectURL(objectUrl);
		};
	}, [file]);

	return src;
};

const useAttachmentSrc = () => {
	const { file, src } = useAssistantState(
		useShallow(({ attachment }): { file?: File; src?: string } => {
			if (!attachment || attachment.type !== "image") return {};
			if (attachment.file) return { file: attachment.file };
			// Only try to filter if content is an array (standard assistant-ui format)
			// Our custom ChatAttachment has content as a string, so skip this
			if (Array.isArray(attachment.content)) {
				const src = attachment.content.filter((c) => c.type === "image")[0]?.image;
				if (src) return { src };
			}
			return {};
		})
	);

	return useFileSrc(file) ?? src;
};

type AttachmentPreviewProps = {
	src: string;
};

const AttachmentPreview: FC<AttachmentPreviewProps> = ({ src }) => {
	const [isLoaded, setIsLoaded] = useState(false);
	return (
		<Image
			src={src}
			alt="Image Preview"
			width={1}
			height={1}
			className={
				isLoaded
					? "aui-attachment-preview-image-loaded block h-auto max-h-[80vh] w-auto max-w-full object-contain"
					: "aui-attachment-preview-image-loading hidden"
			}
			onLoadingComplete={() => setIsLoaded(true)}
			priority={false}
		/>
	);
};

const AttachmentPreviewDialog: FC<PropsWithChildren> = ({ children }) => {
	const src = useAttachmentSrc();

	if (!src) return children;

	return (
		<Dialog>
			<DialogTrigger
				className="aui-attachment-preview-trigger cursor-pointer transition-colors hover:bg-accent/50"
				asChild
			>
				{children}
			</DialogTrigger>
			<DialogContent className="aui-attachment-preview-dialog-content p-2 sm:max-w-3xl [&>button]:rounded-full [&>button]:bg-foreground/60 [&>button]:p-1 [&>button]:opacity-100 [&>button]:ring-0! [&_svg]:text-background [&>button]:hover:[&_svg]:text-destructive">
				<DialogTitle className="aui-sr-only sr-only">Image Attachment Preview</DialogTitle>
				<div className="aui-attachment-preview relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden bg-background">
					<AttachmentPreview src={src} />
				</div>
			</DialogContent>
		</Dialog>
	);
};

const AttachmentThumb: FC = () => {
	const isImage = useAssistantState(({ attachment }) => attachment?.type === "image");
	// Check if actively processing (running AND progress < 100)
	// When progress is 100, processing is done but waiting for send()
	const isProcessing = useAssistantState(({ attachment }) => {
		const status = attachment?.status;
		if (status?.type !== "running") return false;
		// If progress is defined and equals 100, processing is complete
		const progress = (status as { type: "running"; progress?: number }).progress;
		return progress === undefined || progress < 100;
	});
	const src = useAttachmentSrc();

	// Show loading spinner only when actively processing (not when done and waiting for send)
	if (isProcessing) {
		return (
			<div className="flex h-full w-full items-center justify-center bg-muted">
				<Loader2 className="size-6 animate-spin text-muted-foreground" />
			</div>
		);
	}

	return (
		<Avatar className="aui-attachment-tile-avatar h-full w-full rounded-none">
			<AvatarImage
				src={src}
				alt="Attachment preview"
				className="aui-attachment-tile-image object-cover"
			/>
			<AvatarFallback delayMs={isImage ? 200 : 0}>
				<FileText className="aui-attachment-tile-fallback-icon size-8 text-muted-foreground" />
			</AvatarFallback>
		</Avatar>
	);
};

const AttachmentUI: FC = () => {
	const api = useAssistantApi();
	const isComposer = api.attachment.source === "composer";

	const isImage = useAssistantState(({ attachment }) => attachment?.type === "image");
	// Check if actively processing (running AND progress < 100)
	// When progress is 100, processing is done but waiting for send()
	const isProcessing = useAssistantState(({ attachment }) => {
		const status = attachment?.status;
		if (status?.type !== "running") return false;
		const progress = (status as { type: "running"; progress?: number }).progress;
		return progress === undefined || progress < 100;
	});
	const typeLabel = useAssistantState(({ attachment }) => {
		const type = attachment?.type;
		switch (type) {
			case "image":
				return "Image";
			case "document":
				return "Document";
			case "file":
				return "File";
			default:
				return "File"; // Default fallback for unknown types
		}
	});

	return (
		<Tooltip>
			<AttachmentPrimitive.Root
				className={cn(
					"aui-attachment-root relative",
					isImage && "aui-attachment-root-composer only:[&>#attachment-tile]:size-24"
				)}
			>
				<AttachmentPreviewDialog>
					<TooltipTrigger asChild>
						<div
							className={cn(
								"aui-attachment-tile size-14 cursor-pointer overflow-hidden rounded-[14px] border bg-muted transition-opacity hover:opacity-75",
								isComposer && "aui-attachment-tile-composer border-foreground/20",
								isProcessing && "animate-pulse"
							)}
							role="button"
							id="attachment-tile"
							aria-label={isProcessing ? "Processing attachment..." : `${typeLabel} attachment`}
						>
							<AttachmentThumb />
						</div>
					</TooltipTrigger>
				</AttachmentPreviewDialog>
				{isComposer && !isProcessing && <AttachmentRemove />}
			</AttachmentPrimitive.Root>
			<TooltipContent side="top">
				{isProcessing ? (
					<span className="flex items-center gap-1.5">
						<Loader2 className="size-3 animate-spin" />
						Processing...
					</span>
				) : (
					<AttachmentPrimitive.Name />
				)}
			</TooltipContent>
		</Tooltip>
	);
};

const AttachmentRemove: FC = () => {
	return (
		<AttachmentPrimitive.Remove asChild>
			<TooltipIconButton
				tooltip="Remove file"
				className="aui-attachment-tile-remove absolute top-1.5 right-1.5 size-3.5 rounded-full bg-white text-muted-foreground opacity-100 shadow-sm hover:bg-white! [&_svg]:text-black hover:[&_svg]:text-destructive"
				side="top"
			>
				<XIcon className="aui-attachment-remove-icon size-3 dark:stroke-[2.5px]" />
			</TooltipIconButton>
		</AttachmentPrimitive.Remove>
	);
};

export const UserMessageAttachments: FC = () => {
	return (
		<div className="aui-user-message-attachments-end col-span-full col-start-1 row-start-1 flex w-full flex-row justify-end gap-2">
			<MessagePrimitive.Attachments components={{ Attachment: AttachmentUI }} />
		</div>
	);
};

export const ComposerAttachments: FC = () => {
	return (
		<div className="aui-composer-attachments mb-2 flex w-full flex-row items-center gap-2 overflow-x-auto px-1.5 pt-0.5 pb-1 empty:hidden">
			<ComposerPrimitive.Attachments components={{ Attachment: AttachmentUI }} />
		</div>
	);
};

export const ComposerAddAttachment: FC = () => {
	return (
		<ComposerPrimitive.AddAttachment asChild>
			<TooltipIconButton
				tooltip="Add Attachment"
				side="bottom"
				variant="ghost"
				size="icon"
				className="aui-composer-add-attachment size-[34px] rounded-full p-1 font-semibold text-xs hover:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30"
				aria-label="Add Attachment"
			>
				<PlusIcon className="aui-attachment-add-icon size-5 stroke-[1.5px]" />
			</TooltipIconButton>
		</ComposerPrimitive.AddAttachment>
	);
};
