// @ts-nocheck
import { useState, useEffect, useMemo, useRef } from "react";
import Box from "@mui/material/Box";
import Dropzone from "react-dropzone";

import {
  FileBrowser,
  FileContextMenu,
  FileList,
  FileNavbar,
  FileToolbar,
  setChonkyDefaults,
  ChonkyActions,
} from "@aperturerobotics/chonky";
import { ChonkyIconFA } from "@aperturerobotics/chonky-icon-fontawesome";

import {
  getServerFiles,
  createServerFolder,
  deleteServerItem,
  getServerItem,
  moveServerItems,
  previewServerItem,
} from "@mcl/queries";
import { cairoAuthHeader } from "@mcl/util/auth.js";

import { supportedFileTypes } from "./FilePreview.jsx";

export default function MineclusterFiles(props) {
  // Chonky configuration
  setChonkyDefaults({ iconComponent: ChonkyIconFA });
  const fileActions = useMemo(
    () => [
      ChonkyActions.CreateFolder,
      ChonkyActions.UploadFiles,
      ChonkyActions.DownloadFiles,
      ChonkyActions.CopyFiles,
      ChonkyActions.DeleteFiles,
      ChonkyActions.MoveFiles,
    ],
    [],
  );
  const { server: serverId, changePreview } = props;
  const inputRef = useRef(null);
  const [dirStack, setDirStack] = useState(["."]);
  const [files, setFiles] = useState([]);

  const updateFiles = () => {
    const dir = dirStack.join("/");
    getServerFiles(serverId, dir)
      .then((f) => {
        const files = f.map((fi) => ({ ...fi, id: `${dir}/${fi.name}` }));
        setFiles(files ?? []);
      })
      .catch(() =>
        console.error(
          "Couldn't update files, server likely hasn't started yet",
        ),
      );
  };

  useEffect(() => {
    updateFiles();
  }, [dirStack]);

  const getFolderChain = () => {
    if (dirStack.length === 1) return [{ id: "./", name: "Home", isDir: true }];
    return dirStack.map((d, i) => ({
      id: `${dirStack.slice(0, i + 1).join("/")}`,
      name: i === 0 ? "Home" : d,
      isDir: true,
    }));
  };

  const openParentFolder = () => setDirStack(dirStack.slice(0, -1));

  function openItem(payload) {
    const { targetFile: file } = payload;
    if (file && file.isDir) return setDirStack(file.id.split("/"));
    if (!file || file.isDir) return; // Ensure file exists or is dir
    if (supportedFileTypes.includes(file.name.split(".").pop()))
      return previewFile(file);
    return downloadFiles([file]);
  }

  function createFolder() {
    const name = prompt("What is the name of the new folder?");
    const path = [...dirStack, name].join("/");
    createServerFolder(serverId, path).then(updateFiles);
  }

  function deleteItems(files) {
    Promise.all(
      files.map((f) =>
        deleteServerItem(serverId, [...dirStack, f.name].join("/"), f.isDir),
      ),
    )
      .catch((e) => console.error("Error deleting some files!", e))
      .then(updateFiles);
  }

  function uploadFileSelection(e) {
    if (!e.target.files || e.target.files.length === 0) return;
    const { files } = e.target;
    uploadMultipleFiles(files);
  }

  function uploadMultipleFiles(files) {
    Promise.all([...files].map((f) => uploadFile(f)))
      .catch((e) => console.log("Error uploading a file", e))
      .then(updateFiles);
  }

  async function uploadFile(file) {
    const filePath = file.path.startsWith("/") ? file.path : `/${file.path}`;
    const formData = new FormData();
    formData.append("file", file);
    formData.append("id", serverId);
    const path = `${[...dirStack].join("/")}${filePath}`;
    formData.append("path", path);
    await fetch("/api/files/upload", {
      method: "POST",
      body: formData,
      headers: cairoAuthHeader(),
    });
  }

  async function downloadFiles(files) {
    Promise.all(
      files.map((f) =>
        getServerItem(serverId, f.name, [...dirStack, f.name].join("/")),
      ),
    )
      .then(() => console.log("Done downloading files!"))
      .catch((e) => console.error("Error Downloading files!", e));
  }

  function previewFile(file) {
    const { name } = file;
    previewServerItem(serverId, [...dirStack, name].join("/")).then(
      (fileData) =>
        changePreview(name, fileData, [...dirStack, name].join("/")),
    );
  }

  function moveFile(movePayload) {
    const { files: filePayload, destination: destinationPayload } = movePayload;
    if (!destinationPayload.isDir || filePayload.length === 0) return;
    const files = filePayload.map((f) => f.name);
    const dest = destinationPayload.id;
    const origin = dirStack.join("/");
    moveServerItems(serverId, files, dest, origin).then(updateFiles);
  }

  function fileClick(chonkyEvent) {
    const { id: clickEvent, payload } = chonkyEvent;
    if (clickEvent === "open_parent_folder") return openParentFolder();
    if (clickEvent === "create_folder") return createFolder();
    if (clickEvent === "upload_files") return inputRef.current.click();
    if (clickEvent === "download_files")
      return downloadFiles(chonkyEvent.state.selectedFilesForAction);
    if (clickEvent === "delete_files")
      return deleteItems(chonkyEvent.state.selectedFilesForAction);
    if (clickEvent === "move_files") return moveFile(payload);
    if (clickEvent !== "open_files") return; // console.log(clickEvent);
    openItem(payload);
  }

  return (
    <Dropzone onDrop={uploadMultipleFiles}>
      {({ getRootProps }) => (
        <Box
          className="minecluster-files"
          sx={{ height: "calc(100vh - 6rem)" }}
          onDrop={getRootProps().onDrop}
        >
          <input
            type="file"
            id="file"
            ref={inputRef}
            style={{ display: "none" }}
            onChange={uploadFileSelection}
            multiple
          />
          <FileBrowser
            files={files}
            folderChain={getFolderChain()}
            onFileAction={fileClick}
            fileActions={fileActions}
            darkMode={true}
          >
            <FileNavbar />
            <FileToolbar />
            <FileList />
            <FileContextMenu />
          </FileBrowser>
        </Box>
      )}
    </Dropzone>
  );
}
