import { format } from "date-fns";
import {
	Download,
	File,
	FileArchive,
	FileAudio,
	FileCode,
	FileSpreadsheet,
	FileText,
	FileVideo,
	ImageIcon,
	MoreVertical,
	Pencil,
	Trash2,
	TriangleAlert,
} from "lucide-react";
import Link from "next/link";
import { type FormEvent, useState } from "react";
import toast from "react-hot-toast";
import Input from "~/components/custom_ui/input";
import { LoadingPage } from "~/components/loading";
import { Status500 } from "~/components/status-page";
import { Button } from "~/components/ui/button";
import {
	Dialog,
	DialogContent,
	DialogDescription,
	DialogHeader,
	DialogTitle,
} from "~/components/ui/dialog";
import {
	DropdownMenu,
	DropdownMenuContent,
	DropdownMenuItem,
	DropdownMenuTrigger,
} from "~/components/ui/dropdown-menu";
import { Separator } from "~/components/ui/separator";
import { UploadModal } from "~/components/upload_modal";
import { handleDownload } from "~/hooks/filesHooks";
import { cn } from "~/lib/utils";
import { useTranslation } from "~/providers/I18nProvider";
import type {
	Storageindex,
	StorageindexId,
} from "~/schemas/public/Storageindex";
import type { UsersId } from "~/schemas/public/Users";
import { api } from "~/utils/api";

export const AllegatiComp = ({
	userId,
	isAdmin,
}: {
	userId: UsersId;
	isAdmin: boolean;
}) => {
	const { t } = useTranslation();
	const { data: allegati, isLoading: isLoadingAllegati } =
		api.storage.getUserStorage.useQuery({ userId: userId });

	const { mutateAsync: getToken } = api.storage.getStorageToken.useMutation();

	const { mutate: deleteFile } = api.storage.deleteUserStorage.useMutation({
		onMutate: () => {
			const toastId = toast.loading(t.caricamento, {
				icon: "🪛",
			});
			return { toastId };
		},
		onSuccess: async (_error, _variables, context) => {
			await utils.storage.getUserStorage.invalidate({
				userId: userId,
			});
			toast.success(t.allegati.allegato_rimosso, {
				icon: "🗑️",
				id: context?.toastId,
			});
		},
	});

	const { mutate: renameFile } = api.storage.renameFile.useMutation({
		onMutate: () => {
			setEditOpen(false);
			const toastId = toast.loading(t.caricamento, {
				icon: "🪛",
			});
			return { toastId };
		},
		onSuccess: async (_error, _variables, context) => {
			await utils.storage.getUserStorage.invalidate({
				userId: userId,
			});
			toast.success(t.successo, {
				icon: "👍",
				id: context?.toastId,
			});
		},
	});
	const [editData, setEditData] = useState<{
		id: StorageindexId;
		filename: string;
	} | null>(null);
	const [editOpen, setEditOpen] = useState(false);

	const handleEditSubmit = (e: FormEvent<HTMLFormElement>) => {
		e.preventDefault();
		const form = e.currentTarget;
		const formData = new FormData(form);
		if (!formData.get("id") || !formData.get("filename")) {
			return;
		}
		renameFile({
			fileId: formData.get("id") as StorageindexId,
			name: formData.get("filename") as string,
		});
	};

	const utils = api.useUtils();

	if (isLoadingAllegati) return <LoadingPage />;
	if (!allegati) return <Status500 />;

	const from_admin = allegati.filter((a) => a.from_admin);
	const not_from_admin = allegati.filter((a) => !a.from_admin);

	return (
		<div className="flex flex-col space-y-5">
			<h1 className="text-primary text-2xl font-bold">{t.allegati.title}</h1>
			<h1 className="text-xl font-semibold">{t.allegati.da_info}</h1>
			{from_admin && (
				<FileList
					delete_onClick={(id) => deleteFile({ fileId: id, userId })}
					download_onClick={(file) =>
						handleDownload({
							file,
							getToken: async () => await getToken(),
						})
					}
					files={from_admin}
					isAdmin={isAdmin}
					selectHandler={(id, filename) => {
						setEditData({ filename, id });
						setEditOpen(true);
					}}
				/>
			)}
			<Separator />
			<div className="flex items-center gap-3">
				<UploadModal isAdmin={isAdmin} userId={userId} />{" "}
				<span className="text-sm">Max 5 MB per file</span>
			</div>
			<div className="space-y-2 rounded-md border border-orange-500 p-2">
				<div className="flex items-center gap-2 text-orange-500">
					<TriangleAlert className="size-5" />
					{t.importante}:
				</div>
				<span className="text-sm">{t.allegati.disclamer}</span>
			</div>

			{not_from_admin && (
				<FileList
					delete_onClick={(id) => deleteFile({ fileId: id, userId })}
					download_onClick={(file) =>
						handleDownload({
							file,
							getToken: async () => await getToken(),
						})
					}
					files={not_from_admin}
					isAdmin={isAdmin}
					selectHandler={(id, filename) => {
						setEditData({ filename, id });
						setEditOpen(true);
					}}
				/>
			)}
			<EditFileDialog
				data={editData}
				handleEditSubmit={handleEditSubmit}
				onOpenChange={setEditOpen}
				open={editOpen}
			/>
		</div>
	);
};

export const ExtIcon = ({
	ext,
	className,
}: {
	ext: string | null | undefined;
	className?: string;
}) => {
	if (!ext) return <File className={cn("size-5 text-gray-500", className)} />;
	if (ext.includes("pdf")) {
		return <FileText className={cn("size-5 text-red-500", className)} />;
	}
	if (
		ext.includes("image") ||
		["jpg", "jpeg", "png", "gif", "svg", "webp"].some((ext) =>
			ext.includes(ext),
		)
	) {
		return <ImageIcon className={cn("size-5 text-blue-500", className)} />;
	}
	if (
		["html", "css", "js", "jsx", "ts", "tsx", "json", "xml"].some((ext) =>
			ext.includes(ext),
		)
	) {
		return <FileCode className={cn("size-5 text-emerald-500", className)} />;
	}
	if (["xls", "xlsx", "csv"].some((ext) => ext.includes(ext))) {
		return (
			<FileSpreadsheet className={cn("size-5 text-green-600", className)} />
		);
	}
	if (["zip", "rar", "7z", "tar", "gz"].some((ext) => ext.includes(ext))) {
		return <FileArchive className={cn("size-5 text-amber-600", className)} />;
	}
	if (["mp3", "wav", "ogg", "flac"].some((ext) => ext.includes(ext))) {
		return <FileAudio className={cn("size-5 text-purple-500", className)} />;
	}
	if (["mp4", "avi", "mov", "wmv", "webm"].some((ext) => ext.includes(ext))) {
		return <FileVideo className={cn("size-5 text-pink-500", className)} />;
	}
	return <File className={cn("size-5 text-gray-500", className)} />;
};

const EditFileDialog = ({
	open,
	onOpenChange,
	data,
	handleEditSubmit,
}: {
	open: boolean;
	onOpenChange: (status: boolean) => void;
	data: {
		id: StorageindexId;
		filename: string;
	} | null;
	handleEditSubmit: (e: FormEvent<HTMLFormElement>) => void;
}) => {
	const { t } = useTranslation();
	return (
		<Dialog onOpenChange={onOpenChange} open={open}>
			<DialogContent>
				<DialogHeader>
					<DialogTitle>{t.modifica}</DialogTitle>
					<DialogDescription className="sr-only">Edit</DialogDescription>
				</DialogHeader>
				{data && (
					<form method="post" onSubmit={handleEditSubmit}>
						<div className="flex items-center gap-3">
							<label className="sr-only" htmlFor="id">
								ID
							</label>
							<Input
								className="hidden"
								name="id"
								readOnly
								type="text"
								value={data.id}
							/>
							<label className="sr-only" htmlFor="filename">
								filename
							</label>
							<Input
								className="mt-0"
								defaultValue={data.filename || undefined}
								id="filename"
								name="filename"
								placeholder="Modifica messaggio"
								type="text"
							/>
							<Button type="submit">{t.salva}</Button>
						</div>
					</form>
				)}
			</DialogContent>
		</Dialog>
	);
};

interface FileListProps {
	files: Storageindex[];
	delete_onClick: (id: StorageindexId) => void;
	download_onClick: (file: Storageindex) => void;
	isAdmin: boolean;
	selectHandler: (id: StorageindexId, filename: string) => void;
}

function FileList({
	files,
	delete_onClick,
	download_onClick,
	isAdmin,
	selectHandler,
}: FileListProps) {
	return (
		<div className="w-full">
			<div className="rounded-md border">
				<div className="bg-muted/50 text-muted-foreground grid grid-cols-12 gap-2 p-4 text-sm font-medium">
					<div className="col-span-6 md:col-span-8">File</div>
					<div className="col-span-4 md:col-span-3">Data</div>
					<div className="col-span-2 text-right md:col-span-1">Azioni</div>
				</div>
				<div className="divide-y">
					{files.map((file) => (
						<div
							className="hover:bg-muted/50 grid grid-cols-12 items-center gap-2 p-4 text-sm transition-colors"
							key={file.id}
						>
							<div className="col-span-6 flex items-center gap-2 md:col-span-8">
								<div className="shrink-0">
									<ExtIcon ext={file.ext} />
								</div>
								<Link
									aria-label="Allegato"
									className="text-foreground truncate font-medium hover:underline"
									href={`/area-riservata/allegato-view/${file.id}`}
									target="_blank"
								>
									{file.filename}
								</Link>
							</div>

							<div className="text-muted-foreground col-span-4 md:col-span-3">
								{format(file.created_at, "d MMM yyyy")}
							</div>
							<div className="col-span-2 flex justify-end gap-1 md:col-span-1">
								<Button
									aria-label="Download"
									asChild
									className="size-8"
									size="icon"
									title="Download"
									variant="ghost"
								>
									<Button
										className="flex gap-1 text-sm"
										onClick={() => download_onClick(file)}
										variant="outline"
									>
										<Download className="size-4" />
									</Button>
								</Button>

								{isAdmin && (
									<DropdownMenu>
										<DropdownMenuTrigger asChild>
											<Button className="size-8" size="icon" variant="ghost">
												<MoreVertical className="size-4" />
												<span className="sr-only">More options</span>
											</Button>
										</DropdownMenuTrigger>
										<DropdownMenuContent align="end">
											<DropdownMenuItem
												aria-label="Rinomina"
												onClick={() =>
													selectHandler(file.id, file.filename || "")
												}
											>
												<Pencil className="mr-2 size-4" />
												Rinomina
											</DropdownMenuItem>
											<DropdownMenuItem
												aria-label="Elimina"
												className="text-destructive focus:text-destructive"
												onClick={() => delete_onClick(file.id)}
											>
												<Trash2 className="mr-2 size-4" />
												Elimina
											</DropdownMenuItem>
										</DropdownMenuContent>
									</DropdownMenu>
								)}
							</div>
						</div>
					))}
				</div>
			</div>
		</div>
	);
}
