import toast from "react-hot-toast";
import { Upload } from "~/lib/storage_manager";
import { useTranslation } from "~/providers/I18nProvider";
import { api } from "~/utils/api";
import {
  Credenza,
  CredenzaBody,
  CredenzaContent,
  CredenzaDescription,
  CredenzaHeader,
  CredenzaTitle,
  CredenzaTrigger,
} from "~/components/custom_ui/credenza";
import { Button } from "~/components/ui/button";
import { CloudUpload, UploadIcon, X } from "lucide-react";
import {
  FileUpload,
  FileUploadDropzone,
  FileUploadItem,
  FileUploadItemDelete,
  FileUploadItemMetadata,
  FileUploadItemPreview,
  FileUploadItemProgress,
  FileUploadList,
  FileUploadTrigger,
} from "~/components/custom_ui/fileUpload";
import type { UsersId } from "~/schemas/public/Users";
import type { StorageindexId } from "~/schemas/public/Storageindex";
import { useCallback, useState } from "react";

type UploadModalProps = {
  cb_onUpload?: () => void;
  isAdmin?: boolean;
  userId?: UsersId;
};

export const UploadModal = ({
  cb_onUpload,
  isAdmin,
  userId,
}: UploadModalProps) => {
  const { t } = useTranslation();

  return (
    <Credenza>
      <CredenzaTrigger asChild>
        <Button className="flex w-fit gap-2">
          <CloudUpload className="size-6" /> {t.allegati.carica_nuovi}
        </Button>
      </CredenzaTrigger>
      <CredenzaContent className="max-h-[90vh]">
        <CredenzaHeader>
          <CredenzaTitle className="text-center text-2xl font-semibold">
            {t.allegati.carica_nuovi}
          </CredenzaTitle>
          <CredenzaDescription className="sr-only">
            Allegati modal
          </CredenzaDescription>
        </CredenzaHeader>
        <CredenzaBody className="max-h-[80vh] overflow-auto pb-5">
          <UploadComponent
            cb_onUpload={cb_onUpload}
            isAdmin={isAdmin}
            userId={userId}
          />
        </CredenzaBody>
      </CredenzaContent>
    </Credenza>
  );
};

type UploadComponentProps = {
  cb_onUpload?: () => void;
  isAdmin?: boolean;
  userId?: UsersId;
  maxMB?: number;
  maxFiles?: number;
};

export const UploadComponent = ({
  cb_onUpload,
  isAdmin,
  userId,
  maxMB = 5, // Default max size is 5MB
  maxFiles,
}: UploadComponentProps) => {
  const { t } = useTranslation();
  const [files, setFiles] = useState<File[]>([]);
  const [isUploading, setIsUploading] = useState(false);

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

  const { mutate: setUserStorage } = api.storage.addUserStorage.useMutation({
    onMutate: () => {
      toast(t.allegati.allegato_caricato, { icon: "📤" });
    },
    onSettled: async () => {
      await utils.storage.getAll.invalidate();
      await utils.storage.getUserStorage.invalidate({
        userId,
      });
    },
  });

  const acceptedMimeTypes = [
    "image/jpeg", // jpg, jpeg
    "image/png", // png
    "image/webp", // webp
    "text/plain", // txt
    "application/pdf", // pdf
    "application/msword", // doc
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document", // docx
    "application/vnd.ms-excel", // xls
    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // xlsx
    "application/vnd.oasis.opendocument.text", // odt
    "application/vnd.oasis.opendocument.spreadsheet", // ods
  ];

  const utils = api.useUtils();

  const onFileReject = useCallback((file: File, message: string) => {
    toast(
      `${message}\n\n"${file.name.length > 15 ? `${file.name.slice(0, 15)}...` : file.name}" ${t.allegati.file_rejected}`,
    );
  }, []);

  const onFileValidate = useCallback(
    (file: File): string | null => {
      if (maxFiles) {
        // Validate max files
        if (files.length >= maxFiles) {
          return `${t.allegati.file_too_many} ${maxFiles}`;
        }
      }

      // Validate file type
      if (!acceptedMimeTypes.includes(file.type)) {
        return t.allegati.invalid_file_type;
      }
      if (maxMB) {
        // Validate file size
        const MAX_SIZE = maxMB * 1024 * 1024;
        if (file.size > MAX_SIZE) {
          return `${t.allegati.file_too_large} ${MAX_SIZE / (1024 * 1024)}MB`;
        }
      }

      return null;
    },
    [files],
  );

  const onUpload = useCallback(
    async (
      files: File[],
      {
        onProgress,
      }: {
        onProgress: (file: File, progress: number) => void;
      },
    ) => {
      try {
        setIsUploading(true);
        const { status, attachments } = await Upload({
          files: files,
          getToken,
          from_admin: isAdmin ?? true,
        });

        if (userId) {
          for (const storageId of attachments) {
            setUserStorage({
              userId,
              fileId: storageId as StorageindexId,
            });
          }
        }

        files.forEach((file) => {
          const randomDelay = Math.random() * 1000 + 500; // Random delay between 500ms and 1500ms
          let progress = 0;

          const interval = setInterval(() => {
            progress += Math.random() * 10; // Increment progress randomly
            if (progress >= 100) {
              progress = 100;
              clearInterval(interval);
            }
            onProgress(file, progress);
          }, randomDelay / 1); // Adjust interval based on random delay
        });

        if (!status) {
          toast.error(t.allegati.errore_caricamento, {
            icon: "❌",
          });
          setIsUploading(false);
          return;
        }

        toast.success(t.allegati.success_caricamento, {
          icon: "✅",
        });
      } catch (error) {
        setIsUploading(false);

        toast.error(
          error instanceof Error
            ? error.message
            : t.allegati.errore_sconosciuto,
        );
      } finally {
        setIsUploading(false);
        setFiles([]);
        cb_onUpload?.();
        await utils.storage.getAll.invalidate();
      }
    },
    [],
  );

  return (
    <FileUpload
      onFileValidate={onFileValidate}
      className="w-full"
      value={files}
      onValueChange={setFiles}
      onFileReject={onFileReject}
      onUpload={onUpload}
      disabled={isUploading}
      multiple
    >
      <FileUploadDropzone>
        <div className="flex flex-col items-center gap-1">
          <div className="flex items-center justify-center rounded-full border p-2.5">
            <UploadIcon className="text-muted-foreground size-6" />
          </div>
          <p className="text-sm font-medium">{t.allegati.drag_drop}</p>
          <p className="text-muted-foreground text-xs">{t.allegati.oppure}</p>
        </div>
        <FileUploadTrigger asChild>
          <Button variant="outline" size="sm" className="mt-2 w-fit">
            {t.allegati.seleziona}
          </Button>
        </FileUploadTrigger>
      </FileUploadDropzone>
      <FileUploadList>
        {files.map((file, index) => (
          <FileUploadItem key={index} value={file}>
            <FileUploadItemPreview />
            <FileUploadItemMetadata />
            <FileUploadItemDelete asChild>
              <Button variant="ghost" size="icon" className="size-7">
                <X />
              </Button>
            </FileUploadItemDelete>
            <FileUploadItemProgress />
          </FileUploadItem>
        ))}
      </FileUploadList>
    </FileUpload>
  );
};
