"use client";

import React, { memo, useCallback, useMemo, useRef, useState } from "react";
import { Button } from "@/shared/common/ui/button";
import {
  Card,
  CardContent,
  CardHeader,
  CardTitle,
} from "@/shared/common/ui/card";
import { Input } from "@/shared/common/ui/input";
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@/shared/common/ui/tooltip";
import { Alert, AlertDescription, AlertTitle } from "@/shared/common/ui/alert";
import {
  CloudUpload,
  Trash,
  FileType,
  X,
  Info,
  FileUp,
  Plus,
  Check,
} from "lucide-react";
import { ImageCropper } from "./ImageCropper";
import { FilePreview } from "./FilePreview";
import { useToast } from "@/shared/common/ui/use-toast";
import { MAX_FILE_SIZE_MB } from "@/shared/utils/max-file-size";
import {
  getAllowedExtensionsFromAccept,
  getAllowedMimeTypesFromAccept,
  getFinalAllowedFileTypes,
} from "@/shared/utils/get-final-allowed-file-types";
import { ClientSideValidator } from "@/shared/services/validation/ClientSideValidator";
import { FileUploadValidator } from "@/shared/services/validation/FileUploadValidator";

interface UploadFileModalProps {
  onChange: (
    file: File | File[] | null,
    status?: string,
    requiredDocumentId?: string
  ) => void;
  value: File | File[] | null | string;
  fileUploadFields?: any;
  accept?: string[] | null;
  multiple?: boolean;
  onClose?: () => void;
}

export const UploadFileModal = memo(
  ({
    onChange,
    value,
    fileUploadFields,
    accept,
    multiple,
    onClose,
  }: UploadFileModalProps) => {
    const [file, setFile] = useState<File | File[] | null>(null);
    const [croppingFile, setCroppingFile] = useState<File | null>(null);
    const [croppedFile, setCroppedFile] = useState<File | null>(null);
    const [errorMessage, setErrorMessage] = useState<string | null>(null);
    const [fileErrorMessages, setFileErrorMessages] = useState<any[]>([]);

    const openRef = useRef<HTMLInputElement>(null);
    const validatorRef = useRef(new ClientSideValidator());
    const { toast } = useToast();

    const needsCropping = (file: File) => {
      const photoConfig = fileUploadFields?.photoConfiguration;
      const isPhotoConfigEnabled =
        photoConfig === true || photoConfig === "true";
      return (
        isPhotoConfigEnabled &&
        file.type.startsWith("image/") &&
        !["image/gif", "image/svg+xml"].includes(file.type)
      );
    };

    const handleChange = useCallback(
      async (newFile: File | File[] | null) => {
        setErrorMessage(null);
        setFileErrorMessages([]);

        if (newFile) {
          const allowedMimeTypes = accept
            ? getAllowedMimeTypesFromAccept(accept)
            : undefined;
          const allowedExtensions = accept
            ? getAllowedExtensionsFromAccept(accept)
            : undefined;

          if (Array.isArray(newFile)) {
            const validationErrors: any[] = [];
            
            for (let index = 0; index < newFile.length; index++) {
              const item = newFile[index];
              
              // Comprehensive file validation
              const basicValidation = FileUploadValidator.validateFile(item, {
                maxSizeMB: MAX_FILE_SIZE_MB,
                allowedMimeTypes:
                  item.type && allowedMimeTypes?.length
                    ? allowedMimeTypes
                    : undefined,
                allowedExtensions:
                  allowedExtensions?.length ? allowedExtensions : undefined,
              });

              if (!basicValidation.isValid) {
                validationErrors.push({
                  fileIndex: index,
                  error: basicValidation.error || "File validation failed",
                });
                continue;
              }

              // Client-side magic byte validation
              if (accept) {
                const clientValidation = await validatorRef.current.validateUpload(
                  item,
                  item.type,
                  allowedMimeTypes || []
                );

                if (!clientValidation.isValid) {
                  validationErrors.push({
                    fileIndex: index,
                    error: clientValidation.error || "File validation failed",
                  });
                  continue;
                }

              }
            }

            if (validationErrors.length > 0) {
              setFileErrorMessages(validationErrors);
              setErrorMessage(`File validation error`);
              return;
            }
          } else {
            // Comprehensive file validation
            const basicValidation = FileUploadValidator.validateFile(newFile, {
              maxSizeMB: MAX_FILE_SIZE_MB,
              allowedMimeTypes:
                newFile.type && allowedMimeTypes?.length
                  ? allowedMimeTypes
                  : undefined,
              allowedExtensions:
                allowedExtensions?.length ? allowedExtensions : undefined,
            });

            if (!basicValidation.isValid) {
              setErrorMessage(basicValidation.error || "File validation failed");
              return;
            }

            if (accept) {
              // Client-side magic byte validation
              const clientValidation = await validatorRef.current.validateUpload(
                newFile,
                newFile.type,
                allowedMimeTypes || []
              );

              if (!clientValidation.isValid) {
                setErrorMessage(clientValidation.error || "File validation failed");
                return;
              }

            }

            if (needsCropping(newFile)) {
              setCroppingFile(newFile);
              return;
            }
          }
        }

        // Set the file and immediately call onChange to update parent
        const finalFile = multiple
          ? [
              ...(Array.isArray(file) ? file : []),
              ...(Array.isArray(newFile) ? newFile : [newFile]).filter(Boolean),
            ]
          : newFile;
        const cleanedFile = Array.isArray(finalFile)
          ? finalFile.filter((f): f is File => f !== null) // removes nulls
          : finalFile;
        setFile(cleanedFile);

        // Immediately notify parent about the file change
        if (cleanedFile) {
          onChange(
            cleanedFile,
            "selected",
            fileUploadFields?.requiredDocumentId
          );
        } else {
          onChange(null, "removed", fileUploadFields?.requiredDocumentId);
        }
      },
      [fileUploadFields?.photoConfiguration, accept, multiple, file, onChange]
    );
const handleClose = useCallback(() => {
      setCroppingFile(null);
      setFile(null);
      setCroppedFile(null);
      setErrorMessage(null);
      onClose?.();
    }, [onClose]);



    const handleCropComplete = useCallback(
      (croppedFile: File) => {
        setCroppingFile(null);
        setCroppedFile(croppedFile);
        setFile(croppedFile);
        onChange(croppedFile, "selected", fileUploadFields?.requiredDocumentId);
      },
      [onChange, fileUploadFields?.requiredDocumentId]
    );

    const handleCancelCrop = useCallback(() => {
      setCroppingFile(null);
      setFile(null);
      setCroppedFile(null);
      onChange(null, "removed", fileUploadFields?.requiredDocumentId);
    }, [onChange, fileUploadFields?.requiredDocumentId]);

    const handleRemoveFile = useCallback(
      (index?: number) => {
        if (multiple && index !== undefined) {
          const updatedFiles = Array.isArray(file)
            ? file.filter((_, i) => i !== index)
            : null;
          setFile(updatedFiles);
          setFileErrorMessages(
            fileErrorMessages.filter((x) => x?.fileIndex !== index)
          );

          if (updatedFiles && updatedFiles.length > 0) {
            onChange(
              updatedFiles,
              "selected",
              fileUploadFields?.requiredDocumentId
            );
          } else {
            onChange(null, "removed", fileUploadFields?.requiredDocumentId);
          }
        } else {
          setFile(null);
          setCroppedFile(null);
          setErrorMessage(null);
          onChange(null, "removed", fileUploadFields?.requiredDocumentId);
        }
      },
      [
        file,
        multiple,
        fileErrorMessages,
        onChange,
        fileUploadFields?.requiredDocumentId,
      ]
    );

    const isMultipleFileAttached = useMemo(
      () => file && Array.isArray(file),
      [file]
    );

    const isSomeFileAttached = useMemo(() => {
      if (isMultipleFileAttached) {
        return Array.isArray(file) ? file.length > 0 : false;
      }
      return !!file;
    }, [file, isMultipleFileAttached]);

    return (
      <Card className="w-full max-w-md relative">
        <CardHeader>
          <CardTitle>Upload File{multiple && "s"}</CardTitle>
          <Button
            variant="ghost"
            size="icon"
            className="absolute right-4 top-4 h-6 w-6"
            onClick={handleClose}>
            <X className="h-4 w-4" />
          </Button>
        </CardHeader>
        <CardContent>
          <div className="flex flex-col items-center gap-4">
            {croppingFile ? (
              <div className="w-full space-y-4">
                <div className="flex items-center justify-between">
                  <h3 className="text-lg font-bold">Crop Image</h3>
                  <Button
                    variant="ghost"
                    size="icon"
                    onClick={handleCancelCrop}>
                    <X className="h-5 w-5" />
                  </Button>
                </div>
                <Alert>
                  <Info className="h-4 w-4" />
                  <AlertTitle>Note</AlertTitle>
                  <AlertDescription>
                    This image will be cropped to a 3:4 aspect ratio. Please
                    adjust the crop area accordingly.
                  </AlertDescription>
                </Alert>
                <div className="p-4 border rounded-lg bg-muted">
                  <ImageCropper
                    file={croppingFile}
                    onCropComplete={handleCropComplete}
                    aspectRatio={3 / 4}
                  />
                </div>
              </div>
            ) : (
              <>
                <div className={isSomeFileAttached ? "hidden" : "block"}>
                  <div className="flex justify-center">
                    <CloudUpload className="h-12 w-12" />
                  </div>
                  <h2 className="text-xl font-bold text-center mt-4">
                    Upload File{multiple && "s"}
                  </h2>
                </div>

                {isSomeFileAttached && (
                  <div className="relative flex flex-col items-center gap-4 p-4 border rounded-md">
                    <div
                      className={
                        isMultipleFileAttached
                          ? "max-w-[30rem] max-h-[20rem] overflow-auto"
                          : "h-40 w-40"
                      }>
                      {file instanceof File &&
                      file?.type === "application/pdf" ? (
                        <div className="flex flex-col items-center justify-center pt-16">
                          <FileType size={60} className="h-16 w-16" />
                        </div>
                      ) : isMultipleFileAttached ? (
                        <div className="grid grid-cols-2 gap-4">
                          {Array.isArray(file) &&
                            Array.from(file)?.map((f, i) => (
                              <div key={i} className="space-y-2">
                                {f?.type === "application/pdf" ? (
                                  <div className="flex flex-col items-center justify-center pt-16">
                                    <FileType size={60} className="h-16 w-16" />
                                  </div>
                                ) : (
                                  <div
                                    className={`border rounded-md ${
                                      Array.from(file)?.length == 1
                                        ? "h-60"
                                        : "h-48"
                                    } overflow-auto`}>
                                    <FilePreview file={f} type="image" />
                                  </div>
                                )}
                                <p className="w-36 truncate">{f?.name}</p>
                                <Tooltip>
                                  <TooltipTrigger asChild>
                                    <Button
                                      variant="ghost"
                                      size="icon"
                                      className="h-8 w-8"
                                      onClick={() => handleRemoveFile(i)}>
                                      <Trash className="h-4 w-4 text-destructive" />
                                    </Button>
                                  </TooltipTrigger>
                                  <TooltipContent>Remove</TooltipContent>
                                </Tooltip>
                                {fileErrorMessages?.find(
                                  (item) => item.fileIndex === i
                                )?.error && (
                                  <Alert variant="destructive">
                                    <X className="h-4 w-4" />
                                    <AlertDescription>
                                      {
                                        fileErrorMessages?.find(
                                          (item) => item.fileIndex === i
                                        )?.error
                                      }
                                    </AlertDescription>
                                  </Alert>
                                )}
                              </div>
                            ))}
                        </div>
                      ) : (
                        <div className="w-full h-full overflow-auto">
                          <FilePreview
                            file={croppedFile || (file as File)}
                            type="image"
                          />
                        </div>
                      )}
                    </div>

                    {!isMultipleFileAttached &&
                      (croppedFile || file) instanceof File && (
                        <p className="w-36 truncate">
                          {croppedFile
                            ? croppedFile.name
                            : file instanceof File
                            ? file.name
                            : ""}
                        </p>
                      )}
                    {!isMultipleFileAttached && (
                      <Button
                        variant="ghost"
                        size="icon"
                        className="absolute top-2 right-2 h-8 w-8"
                        onClick={() => handleRemoveFile()}>
                        <Trash className="h-4 w-4 text-destructive" />
                      </Button>
                    )}

                    {/* File Selected Indicator */}
                    <div className="flex items-center gap-2 text-primary-600">
                      <Check className="h-4 w-4" />
                      <span className="text-sm font-medium">File selected</span>
                    </div>
                  </div>
                )}

                <p className="text-sm text-muted-foreground text-center">
                  You can attach{" "}
                  {accept
                    ?.map((item) => `${item} files (max ${MAX_FILE_SIZE_MB}MB)`)
                    ?.join(", ")}
                </p>
                {multiple && (
                  <div className="flex items-center gap-2">
                    <Info className="h-4 w-4 text-primary" />
                    <p className="text-sm text-primary">
                      You can attach multiple files
                    </p>
                  </div>
                )}

                <div className="flex flex-col gap-4 w-full">
                  <Input
                    type="file"
                    accept={
                      accept
                        ? getFinalAllowedFileTypes(accept)
                        : "image/png,image/jpeg,application/pdf"
                    }
                    onChange={(e) => {
                      const files = e.target.files;
                      if (!files) return;

                      if (multiple) {
                        handleChange(Array.from(files));
                      } else {
                        handleChange(files[0]);
                      }
                    }}
                    multiple={multiple}
                    className="hidden"
                    ref={openRef}
                  />
                  <Button
                    variant="outline"
                    onClick={() => openRef.current?.click()}
                    className="w-full">
                    {isSomeFileAttached ? (
                      multiple ? (
                        <>
                          <Plus className="mr-2 h-4 w-4" />
                          Add more files
                        </>
                      ) : (
                        <>
                          <FileUp className="mr-2 h-4 w-4" />
                          Change file
                        </>
                      )
                    ) : (
                      <>
                        <FileUp className="mr-2 h-4 w-4" />
                        Select file{multiple ? "s" : ""}
                      </>
                    )}
                  </Button>

                  {/* REMOVED: Continue button - file selection is now immediate */}
                </div>
                {errorMessage && (
                  <Alert variant="destructive">
                    <X className="h-4 w-4" />
                    <AlertDescription>{errorMessage}</AlertDescription>
                  </Alert>
                )}
              </>
            )}
          </div>
        </CardContent>
      </Card>
    );
  }
);

UploadFileModal.displayName = "UploadFileModal";
