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

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
          files={from_admin}
          isAdmin={isAdmin}
          selectHandler={(id, filename) => {
            setEditData({ id, filename });
            setEditOpen(true);
          }}
          delete_onClick={(id) => deleteFile({ userId, fileId: id })}
          download_onClick={(file) =>
            handleDownload({
              file,
              getToken: async () => await getToken(),
            })
          }
        />
      )}
      <Separator />
      <div className="flex items-center gap-3">
        <UploadModal userId={userId} isAdmin={isAdmin} />{" "}
        <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>
        {/*TODO indicare testo corretto per discamer */}
        <span className="text-sm">{t.allegati.disclamer}</span>
      </div>

      {not_from_admin && (
        <FileList
          files={not_from_admin}
          isAdmin={isAdmin}
          selectHandler={(id, filename) => {
            setEditData({ id, filename });
            setEditOpen(true);
          }}
          delete_onClick={(id) => deleteFile({ userId, fileId: id })}
          download_onClick={(file) =>
            handleDownload({
              file,
              getToken: async () => await getToken(),
            })
          }
        />
      )}
      <EditFileDialog
        open={editOpen}
        onOpenChange={setEditOpen}
        data={editData}
        handleEditSubmit={handleEditSubmit}
      />
    </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)} />;
  } else 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)} />;
  } else if (
    ["html", "css", "js", "jsx", "ts", "tsx", "json", "xml"].some((ext) =>
      ext.includes(ext),
    )
  ) {
    return <FileCode className={cn("size-5 text-emerald-500", className)} />;
  } else if (["xls", "xlsx", "csv"].some((ext) => ext.includes(ext))) {
    return (
      <FileSpreadsheet className={cn("size-5 text-green-600", className)} />
    );
  } else if (
    ["zip", "rar", "7z", "tar", "gz"].some((ext) => ext.includes(ext))
  ) {
    return <FileArchive className={cn("size-5 text-amber-600", className)} />;
  } else if (["mp3", "wav", "ogg", "flac"].some((ext) => ext.includes(ext))) {
    return <FileAudio className={cn("size-5 text-purple-500", className)} />;
  } else if (
    ["mp4", "avi", "mov", "wmv", "webm"].some((ext) => ext.includes(ext))
  ) {
    return <FileVideo className={cn("size-5 text-pink-500", className)} />;
  } else {
    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 open={open} onOpenChange={onOpenChange}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>{t.modifica}</DialogTitle>
          <DialogDescription className="sr-only">Edit</DialogDescription>
        </DialogHeader>
        {data && (
          <form onSubmit={handleEditSubmit} method="post">
            <div className="flex items-center gap-3">
              <label htmlFor="id" className="sr-only">
                ID
              </label>
              <Input
                type="text"
                className="hidden"
                name="id"
                value={data.id}
                readOnly
              />
              <label htmlFor="filename" className="sr-only">
                filename
              </label>
              <Input
                type="text"
                placeholder="Modifica messaggio"
                className="mt-0"
                id="filename"
                name="filename"
                defaultValue={data.filename || undefined}
              />
              <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
              key={file.id}
              className="hover:bg-muted/50 grid grid-cols-12 items-center gap-2 p-4 text-sm transition-colors"
            >
              <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"
                  href={`/area-riservata/allegato-view/${file.id}`}
                  target="_blank"
                  className="text-foreground truncate font-medium hover:underline"
                >
                  {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"
                  variant="ghost"
                  size="icon"
                  asChild
                  className="size-8"
                  title="Download"
                >
                  <Button
                    variant="outline"
                    className="flex gap-1 text-sm"
                    onClick={() => download_onClick(file)}
                  >
                    <Download className="size-4" />
                  </Button>
                </Button>

                {isAdmin && (
                  <DropdownMenu>
                    <DropdownMenuTrigger asChild>
                      <Button variant="ghost" size="icon" className="size-8">
                        <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"
                        onClick={() => delete_onClick(file.id)}
                        className="text-destructive focus:text-destructive"
                      >
                        <Trash2 className="mr-2 size-4" />
                        Elimina
                      </DropdownMenuItem>
                    </DropdownMenuContent>
                  </DropdownMenu>
                )}
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}
