"use client";

import React, { SetStateAction, useCallback, useState } from "react";
import { useDropzone, FileRejection } from "react-dropzone";
import { Button } from "@/components/ui/button";
import { Progress } from "@/components/ui/progress";
import { Upload, X, Loader2, FileText } from "lucide-react";
import privateApi from "@/service/http/privateCall.axios";
import { useQueryClient } from "@tanstack/react-query";
import { API_URL } from "@/constants";
import { DocumentType } from "@/types";
import { MeResponse } from "@/hooks";

const ACCEPTED_TYPES = {
  "application/pdf": [".pdf"],
  "image/jpeg": [".jpg", ".jpeg"],
  "image/webp": [".webp"],
  "image/png": [".png"],
};

type UploadItem = {
  file: File;
  progress: number;
  status: "idle" | "uploading" | "done" | "error";
  xhr?: XMLHttpRequest;
};

type BaseProps = {
  fileType: "image" | "document";
  documentType: DocumentType;
  maxSize?: number;
  autoUpload?: boolean;
};

type SingleProps = {
  multiple?: false;
  output?: string;
  setOutput?: React.Dispatch<React.SetStateAction<string>>;
};

type MultipleProps = {
  multiple: true;
  output?: string[];
  setOutput?: React.Dispatch<React.SetStateAction<string[]>>;
};

type Props = BaseProps & (SingleProps | MultipleProps);

export default function UploadDropzone({
  fileType,
  multiple,
  documentType,
  maxSize = 5 * 1024 * 1024,
  autoUpload = false,
  output,
  setOutput,
}: Props) {
  const qc = useQueryClient();
  const user: MeResponse = qc.getQueryData(["me"])!;

  const [items, setItems] = useState<UploadItem[]>([]);
  const [error, setError] = useState<string | null>(null);

  const getPreviewUrl = (file: File) =>
    file.type.startsWith("image/") ? URL.createObjectURL(file) : null;

  const onDrop = useCallback(
    (accepted: File[], rejected: FileRejection[]) => {
      if (!multiple && accepted.length > 1) {
        setError("فقط یک فایل مجاز است");
        return;
      }

      if (rejected.length) {
        const reason = rejected[0].errors[0];
        setError(
          reason.code === "file-too-large"
            ? "حجم فایل بیشتر از حد مجاز است"
            : "فرمت فایل مجاز نیست",
        );
        return;
      }

      const newItems: UploadItem[] = accepted.map((file) => ({
        file,
        progress: 0,
        status: "idle",
      }));

      setItems((prev) => (multiple ? [...prev, ...newItems] : newItems));
      setError(null);

      if (autoUpload) {
        newItems.forEach((item) => startUpload(item.file));
      }
    },
    [autoUpload],
  );

  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    onDrop,
    multiple: multiple ?? false,
    maxSize,
    accept: ACCEPTED_TYPES,
  });

  const startUpload = async (file: File) => {
  
    try {
      console.log('running')
      setItems((prev) =>
        prev.map((i) => (i.file === file ? { ...i, status: "uploading" } : i)),
      );

      const tokenRes = await privateApi.post("/upload/request", {
        userId: user.data.id,
        type: fileType,
      });

      console.log(tokenRes);
      const uploadToken = tokenRes.data?.data?.uploadToken;
      if (!uploadToken) throw new Error();

      const xhr = new XMLHttpRequest();

      setItems((prev) =>
        prev.map((i) => (i.file === file ? { ...i, xhr } : i)),
      );

      const formData = new FormData();
      formData.append("file", file);
      formData.append("type", documentType.toString());

      xhr.upload.onprogress = (e) => {
        if (e.lengthComputable) {
          setItems((prev) =>
            prev.map((i) =>
              i.file === file
                ? {
                    ...i,
                    progress: Math.round((e.loaded / e.total) * 100),
                  }
                : i,
            ),
          );
        }
      };

      xhr.onload = () => {
        setItems((prev) =>
          prev.map((i) =>
            i.file === file ? { ...i, status: "done", progress: 100 } : i,
          ),
        );
        const response = JSON.parse(xhr.responseText);
        const newId = response.data.document.id;

        if (multiple) {
          setOutput?.((prev: string[]) => [...(prev || []), newId]);
        } else {
          setOutput?.(newId);
        }
      };

      xhr.onerror = () => {
        setItems((prev) =>
          prev.map((i) => (i.file === file ? { ...i, status: "error" } : i)),
        );
      };

      xhr.open("POST", `${API_URL}/upload/upload`);
      xhr.setRequestHeader("x-upload-token", uploadToken);
      xhr.send(formData);
    } catch {
      setItems((prev) =>
        prev.map((i) => (i.file === file ? { ...i, status: "error" } : i)),
      );
    }
  };

  const cancelUpload = (file: File) => {
    const item = items.find((i) => i.file === file);
    item?.xhr?.abort();

    setItems((prev) =>
      prev.map((i) =>
        i.file === file ? { ...i, status: "idle", progress: 0 } : i,
      ),
    );
  };

  return (
    <div className="w-full max-w-md space-y-4">
      <div
        {...getRootProps()}
        className={`rounded-xl border-2 border-dashed p-6 text-center cursor-pointer
        ${isDragActive ? "border-primary bg-primary/5" : "border-muted"}`}
      >
        <input {...getInputProps()} />
        <Upload className="mx-auto mb-2 h-6 w-6 text-muted-foreground" />
        <p className="text-sm text-muted-foreground">
          فایل‌ها را بکشید یا کلیک کنید
        </p>
      </div>

      {items.map(({ file, progress, status }) => {
        const preview = getPreviewUrl(file);

        return (
          <div key={file.name} className="rounded-xl border p-4 space-y-3">
            <div className="flex items-center gap-3">
              <div className="h-14 w-14 border rounded flex items-center justify-center overflow-hidden">
                {preview ? (
                  <img src={preview} className="h-full w-full object-cover" />
                ) : (
                  <FileText className="h-6 w-6 text-muted-foreground" />
                )}
              </div>

              <span className="flex-1 truncate text-sm">{file.name}</span>

              {status === "idle" && (
                <X
                  className="h-4 w-4 cursor-pointer"
                  onClick={() =>
                    setItems((prev) => prev.filter((i) => i.file !== file))
                  }
                />
              )}
            </div>

            <Progress value={progress} />

            {status === "idle" && !autoUpload && (
              <Button className="w-full" onClick={() => startUpload(file)}>
                شروع آپلود
              </Button>
            )}

            {status === "uploading" && (
              <Button
                variant="destructive"
                className="w-full flex gap-2"
                onClick={() => cancelUpload(file)}
              >
                <Loader2 className="h-4 w-4 animate-spin" />
                کنسل
              </Button>
            )}

            {status === "error" && (
              <p className="text-sm text-destructive">آپلود ناموفق بود</p>
            )}
          </div>
        );
      })}
    </div>
  );
}
