import React, { useRef, useState, useEffect, useMemo } from "react";
import PropTypes from "prop-types";
import ClearIcon from "@mui/icons-material/Clear";
import { Button } from "../Button";
import { ProgressBar } from "../ProgressBar";
import "./FileUpload.styles.scss";
import { ReactComponent as UploadDownloadIcon } from "../../assets/uploadDownloadIcon.svg";
import uploadDownloadIcon from "../../assets/uploadDownloadIcon.svg";
import downArrow from "../../assets/downArrow.svg";
import fileUploadDownloadIcon from "../../assets/fileUploadDownloadIcon.svg";
import fileUploadRetryIcon from "../../assets/fileUploadRetryIcon.svg";
import uploadCloseIcon from "../../assets/upload-close-icon.svg";
import uploadPauseIcon from "../../assets/upload-pause-icon.svg";
import { Menu } from "../Menu";
import { toCamelCase } from "../../utils/helper";
export const sizeConventions = [
  "B",
  "KB",
  "MB",
  "GB",
  "TB",
  "PB",
  "EB",
  "ZB",
  "YB",
];

const fileTypes = {
  pdf: ["application/pdf"],
  image: [
    "image/png",
    "image/jpeg",
    "image/jpg",
    "image/gif",
    "image/bmp",
    "image/webp",
    "image/svg+xml",
    "image/tiff",
  ],
  xls: [
    "application/vnd.ms-excel",
    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  ],
  xlsx: [
    "application/vnd.ms-excel",
    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  ],
  csv: ["text/csv"],
  text: ["text/plain"],
  html: ["text/html"],
  audio: ["audio/mpeg", "audio/wav", "audio/ogg"],
  video: ["video/mp4", "video/webm", "video/ogg"],
  zip: ["application/x-zip-compressed", "application/zip"],

  default: ["application/octet-stream"],
};

export const FileUpload = ({
  fileList,
  onFileListChange,
  disabled = false,
  numberOfFiles: numFiles = 1,
  validFileTypes = [
    { fileType: "xlsx", templateDownloader: undefined, typeOverride: false },
    { fileType: "csv", templateDownloader: undefined, typeOverride: false },
  ],
  primaryButtonLabel,
  secondaryButtonLabel,
  onPrimaryButtonClick,
  primaryButtonProps,
  onSecondaryButtonClick,
  secondaryButtonProps,
  onClose,
  customFailedActionButton,
  options,
  selectedValues,
  onMenuPrimaryButtonClick,
  onTertiaryButtonClick,
  showHeader = true,
  headerTitle = "Upload Your File",
  headerSubtitle,
  showCloseIcon = true,
  width,
  height,
}) => {
  const wrapperRef = useRef(null);
  const fileUploadRef = useRef(null);
  const hiddenFileUploadRef = useRef(null);
  const containerRef = useRef(null);
  const [currentFileType, setCurrentFileType] = useState(
    validFileTypes[0]?.fileType
  );
  const [isError, setIsError] = useState(false);
  const [isDraggedOver, setIsDraggedOver] = useState(false);
  const [showDownLoadMenu, setShowDownLoadMenu] = useState(false);

  const numberOfFiles = numFiles >= 1 ? Math.floor(numFiles) : 1;
  const uploadSubtitle = headerSubtitle || `You can upload up to ${numberOfFiles} file${numberOfFiles > 1 ? "s" : ""}`;
  const [isOpen, setIsOpen] = useState(false);
  const [anchorEl, setAnchorEl] = useState(null);
  const [selected, setSelected] = useState(
    (selectedValues || []).map((val) => toCamelCase(val))
  );

  const menuOptions = useMemo(
    () =>
      options?.map((item) => ({
        label: item,
        value: toCamelCase(item),
        onClick: () =>
          setSelected((prev) => {
            const val = toCamelCase(item);
            return prev?.includes(val)
              ? prev.filter((v) => v !== val)
              : [...prev, val];
          }),
      })),
    [options]
  );

  useEffect(() => {
    const fileType = validFileTypes.map((file) => fileTypes[file.fileType]);
    setCurrentFileType(fileType.join(","));
  }, [validFileTypes]);

  const onDragEnter = () => {
    setIsDraggedOver(true);
    wrapperRef.current.classList.add("ia-fileUpload-dragOver");
  };

  const onDragLeave = () => {
    setIsDraggedOver(false);
    wrapperRef.current.classList.remove("ia-fileUpload-dragOver");
  };

  const onDrop = (e) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDraggedOver(false);
    wrapperRef.current.classList.remove("ia-fileUpload-dragOver");
    onFileDrop(e, true);
  };

  const onFileDrop = (e, isDragEvent = false) => {
    let newFiles;
    if (isDragEvent) {
      newFiles = e.dataTransfer && e.dataTransfer.files;
    } else {
      newFiles = e.target.files;
    }

    if (!newFiles || newFiles.length === 0) return;

    const filesToAdd = [];
    const maxFilesToAdd = numberOfFiles - fileList.length;

    // Process up to the maximum allowed files
    for (let i = 0; i < Math.min(newFiles.length, maxFilesToAdd); i++) {
      const newFile = newFiles[i];

      // Check if file type is valid
      if (
        !validFileTypes.find((vft) =>
          vft.typeOverride
            ? vft.fileType === newFile.type
            : fileTypes[vft.fileType]?.includes(newFile.type)
        )
      ) {
        setIsError(true);
        continue;
      }

      // Check if file already exists
      if (
        fileList.find(
          (f) => f.file.name === newFile.name && f.file.size === newFile.size
        ) ||
        filesToAdd.find(
          (f) => f.file.name === newFile.name && f.file.size === newFile.size
        )
      ) {
        continue;
      }

      filesToAdd.push({
        file: newFile,
        progress: 0,
        isUploadRunning: false,
        failed: false,
      });
    }

    if (filesToAdd.length > 0) {
      setIsError(false);
      const updatedList = [...fileList, ...filesToAdd];
      onFileListChange(updatedList);
    }
  };

  const fileRemove = (file) => {
    const updatedList = [...fileList];

    updatedList.splice(fileList.indexOf(file), 1);

    onFileListChange(updatedList);
  };

  const onUploadClick = () => {
    hiddenFileUploadRef.current.click();
  };

  const templateDownloader = useMemo(() => {
    if (!Array.isArray(validFileTypes)) return null;
    return validFileTypes.find((vft) => vft.templateDownloader);
  }, [validFileTypes]);

  const handleTemplateDownloadMenu = () => {
    setShowDownLoadMenu(!showDownLoadMenu);
  };

  const activateOnEnterOrSpace = (handler) => (e) => {
    if (!handler) return;
    if (e.key === "Enter" || e.key === " ") {
      e.preventDefault();
      handler(e);
    }
  };

  const handleClickOutside = (event) => {
    if (
      !event.target.closest(".ia-fileUpload-validFileType-container") &&
      !event.target.closest(".ia-fileUpload-validFileType-menu-item")
    ) {
      setShowDownLoadMenu(false);
      setIsOpen(false);
    }
  };

  useEffect(() => {
    const handleEscape = (event) => {
      if (event.key === "Escape") {
        setShowDownLoadMenu(false);
      }
    };
    if (showDownLoadMenu) {
      document.addEventListener("click", handleClickOutside);
      document.addEventListener("keydown", handleEscape);
    }
    return () => {
      document.removeEventListener("click", handleClickOutside);
      document.removeEventListener("keydown", handleEscape);
    };
  }, [showDownLoadMenu]);

  const selectedFileType = useMemo(() => {
    return (
      validFileTypes.find((vft) => vft.fileType === "xlsx")?.fileType ||
      validFileTypes[0]?.fileType
    );
  }, [validFileTypes]);

  return (
    <div ref={containerRef} className="ia-fileUpload-container" style={{ width: width }}>
      {showHeader && (
      <div className="ia-fileUpload-container-header">
        <div className="ia-fileUpload-container-header-title">
        {headerTitle && (
          <span className="ia-fileUpload-container-header-title-primary">
            {headerTitle}
          </span>
          )}
          {uploadSubtitle && (
          <span className="ia-fileUpload-container-header-title-secondary">
            {uploadSubtitle}
          </span>
          )}
        </div>
         {showCloseIcon && onClose && (
        <ClearIcon
          className="ia-fileUpload-container-header-closeIcon"
          onClick={onClose}
          tabIndex={0}
          role="button"
          onKeyDown={(e) => {
            if (e.key === "Enter" || e.key === " ") {
              onClose(e);
            }
          }}
          aria-label="Close"
        />
        )}
      </div>
      )}
      <input
        ref={hiddenFileUploadRef}
        type="file"
        onChange={onFileDrop}
        style={{ display: "none" }}
        accept={currentFileType}
        value=""
        multiple={numberOfFiles > 1}
      />
      {fileList.length >= numberOfFiles ? null : (
        <div
          ref={wrapperRef}
          style={{ height: height }}
          className={`ia-styles ia-fileUpload ${
            isError ? "ia-fileUpload-error" : ""
          } ${disabled ? "ia-fileUpload-disabled" : ""}`}
          onDragEnter={onDragEnter}
          onDragLeave={onDragLeave}
          onDrop={onDrop}
          onDragOver={(e) => e.preventDefault()}
        >
          {isDraggedOver ? (
            <div className="ia-fileUpload-dragOverLabel">
              File drop in progress...
            </div>
          ) : (
            <div className="ia-fileUpload-label">
              <div className="ia-fileUpload-label-primary">
                {isError ? (
                  "File type not supported"
                ) : (
                  <p className="ia-fileUpload-label">Drag your files here or</p>
                )}
                <input
                  ref={fileUploadRef}
                  type="file"
                  onChange={onFileDrop}
                  value=""
                  accept={currentFileType}
                  title={fileList[0]?.file.name}
                  multiple={numberOfFiles > 1}
                  tabIndex={-1}
                  aria-hidden="true"
                />
                <Button
                  onClick={onUploadClick}
                  variant="url"
                  label="Browse Files"
                  onDragEnter={onDragEnter}
                  disabled={isDraggedOver}
                >
                  Choose File
                </Button>
              </div>
              <p className="ia-fileUpload-label-secondary">
                support{validFileTypes.length > 1 ? "s" : ""}{" "}
                {validFileTypes.map((vft) => `.${vft.fileType}`).join(", ")}
              </p>
            </div>
          )}
          {/* <span className="ia-fileUpload-hr">OR</span> */}
        </div>
      )}

      {templateDownloader ? (
        <div className="ia-fileUpload-validFileType">
          <p className="ia-fileUpload-label-secondary">Simplify your upload!</p>{" "}
          <div className="ia-fileUpload-validFileType-container">
            <div
              onClick={(e) => {
                setIsOpen(true);
                setAnchorEl(e.currentTarget);
                validFileTypes.length > 1 || options
                  ? handleTemplateDownloadMenu()
                  : templateDownloader.templateDownloader();
              }}
              onKeyDown={activateOnEnterOrSpace(
                validFileTypes.length > 1
                  ? handleTemplateDownloadMenu
                  : templateDownloader.templateDownloader
              )}
              role="button"
              tabIndex={0}
              aria-haspopup={validFileTypes.length > 1 ? "menu" : undefined}
              aria-expanded={
                validFileTypes.length > 1 ? showDownLoadMenu : undefined
              }
              aria-label="Download template"
              style={{ display: "flex", alignItems: "center", gap: "4px" }}
            >
              <Button
                data-fileUpload="templateDownload"
                variant="url"
                tabIndex={-1}
              >
                {"Download template"}
              </Button>
              <img
                src={
                  validFileTypes.length > 1 || options
                    ? downArrow
                    : uploadDownloadIcon
                }
                alt=""
                aria-hidden="true"
                className={`ia-fileUpload-validFileType-arrow ${
                  (validFileTypes.length > 1 || options) && showDownLoadMenu
                    ? "rotate"
                    : ""
                }`}
              />

              {options && isOpen && (
                <Menu
                  anchorEl={anchorEl}
                  iconPlacement="left"
                  onClose={() => setIsOpen(false)}
                  open={isOpen}
                  options={menuOptions}
                  menuContainerClassName={"ia-fileUpload-validFileType-menu"}
                  MenuProps={{
                    anchorOrigin: {
                      vertical: "top",
                      horizontal: "left",
                    },
                    transformOrigin: {
                      vertical: "bottom",
                      horizontal: "left",
                    },
                  }}
                  selected={selected}
                  withActionButtons
                  withCheckbox
                  onPrimaryButtonClick={() =>
                    onMenuPrimaryButtonClick?.(selectedFileType, selected)
                  }
                  primaryButtonProps={{
                    label: selectedFileType,
                    icon: <UploadDownloadIcon />,
                  }}
                  {...(validFileTypes.length > 1 && {
                    tertiaryButtonLabel: validFileTypes.find(
                      (vft) => vft.fileType !== "xlsx"
                    )?.fileType,
                    tertiaryButtonProps: { icon: <UploadDownloadIcon /> },
                    onTertiaryButtonClick: () =>
                      onTertiaryButtonClick?.(selected),
                  })}
                />
              )}
            </div>
            {showDownLoadMenu && !options && (
              <div className="ia-fileUpload-validFileType-menu" role="menu">
                {validFileTypes.map((vft) => (
                  <span
                    key={vft.fileType}
                    className="ia-fileUpload-validFileType-menu-item"
                    onClick={() => {
                      vft.templateDownloader();
                      setShowDownLoadMenu(false);
                    }}
                    onKeyDown={activateOnEnterOrSpace(() => {
                      vft.templateDownloader();
                      setShowDownLoadMenu(false);
                    })}
                    role="menuitem"
                    tabIndex={0}
                  >
                    {`.${vft.fileType}`}
                  </span>
                ))}
              </div>
            )}
          </div>
        </div>
      ) : null}

      {options?.length > 0 && templateDownloader && (
        <div className="ia-template-preview">
          <h3 className="ia-template-preview__title">Template Preview</h3>
          <div className="ia-template-preview__grid-wrapper">
            <table className="ia-template-preview__table">
              <thead>
                <tr>
                  <th className="ia-template-preview__row-header"></th>
                  {Array.from({ length: 9 }, (_, i) =>
                    String.fromCharCode(65 + i)
                  ).map((letter) => (
                    <th
                      key={letter}
                      className="ia-template-preview__col-header"
                    >
                      {letter}
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td className="ia-template-preview__row-header">1</td>
                  {Array.from({ length: 9 }, (_, i) => (
                    <td key={i} className="ia-template-preview__cell">
                      {selected[i] ? (
                        <div className="ia-template-preview__cell-value">
                          {selected[i].charAt(0).toUpperCase() +
                            selected[i].slice(1)}
                        </div>
                      ) : null}
                    </td>
                  ))}
                </tr>
                {[2, 3].map((row) => (
                  <tr key={row}>
                    <td className="ia-template-preview__row-header">{row}</td>
                    {Array.from({ length: 9 }, (_, i) => (
                      <td key={i} className="ia-template-preview__cell"></td>
                    ))}
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {fileList.map((item) => {
        let fileSize = item.file.size;

        let i = 0;
        while (fileSize > 1024) {
          fileSize = fileSize / 1024;
          i += 1;
        }

        return (
          <div key={item.file.name} className="ia-fileUpload-previewItem">
            <div className="ia-fileUpload-previewItem-exceptProgress">
              <div className="ia-fileUpload-previewItem-details">
                {item.isUploadRunning ? null : (
                  <div
                    className={`ia-fileUpload-previewItemIcon ${
                      item.failed || item.disabled
                        ? "ia-fileUpload-previewItemIcon-failed"
                        : ""
                    } ${Object.keys(fileTypes).find((key) =>
                      fileTypes[key].includes(item.file.type)
                    )}`}
                  />
                )}

                <div className="ia-fileUpload-previewItem-info">
                  <span
                    className={`ia-fileUpload-previewItem-name ${
                      item.failed || item.disabled
                        ? "ia-fileUpload-previewItem-name-failed"
                        : ""
                    }`}
                  >
                    {item.file.name}
                  </span>

                  <span
                    className={`ia-fileUpload-previewItem-size ${
                      item.failed ? "uploadFailed" : ""
                    } ${item.isUploadRunning ? "uploading" : ""} ${
                      item.disabled ? "disabled" : ""
                    }`}
                  >
                    {item.failed
                      ? item.failedMessage || "Upload failed"
                      : fileSize.toFixed(0) + sizeConventions[i]}
                  </span>
                </div>
              </div>

              <div
                className={`ia-fileUpload-previewItem-actions ${
                  item.failed || item.disabled
                    ? "ia-fileUpload-previewItem-actions-failed"
                    : ""
                }`}
              >
                {item.failed ? (
                  item.failedMessage ? (
                    customFailedActionButton
                  ) : (
                    <>
                      <img
                        src={fileUploadDownloadIcon}
                        alt="fileUploadDownloadIcon"
                        className="ia-fileUpload-previewItem-action removeIcon"
                        onClick={() => fileRemove(item)}
                        role="button"
                        tabIndex={item.disabled ? -1 : 0}
                        aria-label={`Remove ${item.file.name}`}
                        onKeyDown={activateOnEnterOrSpace(() =>
                          fileRemove(item)
                        )}
                        style={
                          item.disabled
                            ? { opacity: 0.5, pointerEvents: "none" }
                            : {}
                        }
                      />
                      {item.onRetry ? (
                        <img
                          src={fileUploadRetryIcon}
                          alt="fileUploadRetryIcon"
                          className="ia-fileUpload-previewItem-action"
                          onClick={item.onRetry}
                          role="button"
                          tabIndex={item.disabled ? -1 : 0}
                          aria-label={`Retry upload of ${item.file.name}`}
                          onKeyDown={activateOnEnterOrSpace(item.onRetry)}
                          style={
                            item.disabled
                              ? { opacity: 0.5, pointerEvents: "none" }
                              : {}
                          }
                        />
                      ) : null}
                    </>
                  )
                ) : (
                  <>
                    {item.onPause ? (
                      <img
                        src={uploadPauseIcon}
                        alt="uploadPauseIcon"
                        className="ia-fileUpload-previewItem-action"
                        onClick={item.onPause}
                        role="button"
                        tabIndex={item.disabled ? -1 : 0}
                        aria-label={`Pause upload of ${item.file.name}`}
                        onKeyDown={activateOnEnterOrSpace(item.onPause)}
                        style={
                          item.disabled
                            ? { opacity: 0.5, pointerEvents: "none" }
                            : {}
                        }
                      />
                    ) : null}
                    <img
                      src={
                        item.isUploadRunning
                          ? uploadCloseIcon
                          : fileUploadDownloadIcon
                      }
                      alt="fileUploadDownloadIcon"
                      className="ia-fileUpload-previewItem-action removeIcon"
                      onClick={() => fileRemove(item)}
                      role="button"
                      tabIndex={item.disabled ? -1 : 0}
                      aria-label={
                        item.isUploadRunning
                          ? `Cancel upload of ${item.file.name}`
                          : `Remove ${item.file.name}`
                      }
                      onKeyDown={activateOnEnterOrSpace(() =>
                        fileRemove(item)
                      )}
                      style={
                        item.disabled
                          ? { opacity: 0.5, pointerEvents: "none" }
                          : {}
                      }
                    />
                  </>
                )}
              </div>
            </div>

            {item.isUploadRunning ? (
              <div className="ia-fileUpload-progress">
                <ProgressBar
                  showTime={item.timeRemaining}
                  time={item.timeRemaining}
                  value={item.progress}
                />
              </div>
            ) : null}
          </div>
        );
      })}

      <div className="ia-fileUpload-actions">
        {secondaryButtonLabel && (
          <Button
            variant="tertiary"
            onClick={onSecondaryButtonClick}
            {...secondaryButtonProps}
          >
            {secondaryButtonLabel}
          </Button>
        )}
        {primaryButtonLabel && (
          <Button
            variant="primary"
            onClick={onPrimaryButtonClick}
            disabled={fileList.length === 0}
            {...primaryButtonProps}
          >
            {primaryButtonLabel}
          </Button>
        )}
      </div>
    </div>
  );
};

FileUpload.propTypes = {
  fileList: PropTypes.arrayOf(
    PropTypes.shape({
      file: PropTypes.object,
      progress: PropTypes.number,
      failed: PropTypes.bool,
      isUploadRunning: PropTypes.bool,
      timeRemaining: PropTypes.number,
      onPause: PropTypes.func,
      onRetry: PropTypes.func,
    })
  ),
  numberOfFiles: PropTypes.number,
  disabled: PropTypes.bool,
  validFileTypes: PropTypes.arrayOf(
    PropTypes.shape({
      fileType: PropTypes.string,
      templateDownloader: PropTypes.func,
      typeOverride: PropTypes.bool,
    })
  ),
  onFileListChange: PropTypes.func,
  showHeader: PropTypes.bool,
  showCloseIcon: PropTypes.bool,
  headerTitle: PropTypes.string,
  headerSubtitle: PropTypes.string,
  width: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
  ]),
  height: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
  ]),
};

