import * as React from "react";
import * as Yup from "yup";
import { createUseStyles } from "react-jss";
import { useState } from "@theia/core/shared/react";
import { Form, Formik, FormikHelpers } from "formik";
import { OpenFileDialogProps } from "@theia/filesystem/lib/browser";
import {
  emptyInputErrorMessage,
  EScreenView,
  LocalStorageKey,
  RCloneEndPoints,
  SyncActionDirection,
  PathSelectInputType,
  destinationFileErrorMessage,
} from "../../../../constants";
import { useCommonStyles } from "../../StorjWidget.style";
import fetchRClone from "../../../../helpers/fetchRClone";
import BackButton from "../../../BackButton";
import URI from "@theia/core/lib/common/uri";
import RemotePathSelectorModal from "../../../RemotePathSelectorModal";
import { useStorjWidgetContext } from "../../StorjWidget.context";
import PathSelectInput from "../../../PathSelectInput";
import { saveJobsToStorage } from "../../../../helpers/saveJobToStorage";
import { removeFileNameFromPath } from "../../../../helpers/pathHelpers";

const AccessGrantValidationSchema = Yup.object().shape({
  jobSessionPath: Yup.string().required(emptyInputErrorMessage),
  remoteStoragePath: Yup.string().required(emptyInputErrorMessage),
});

const useStyles = createUseStyles({
  actionContainer: {
    display: "flex",
    alignItems: "center",
    marginBottom: 16,
    justifyContent: "space-between",
  },
  image: {
    backgroundImage: "var(--galileo-assets-cloud-jobsession)",
    backgroundSize: "contain",
    height: 200,
    marginRight: 16,
    backgroundPosition: "center",
    backgroundRepeat: "no-repeat",
    marginTop: 40,
  },
  imageToCloud: {
    composes: "$image",
    backgroundImage: "var(--galileo-assets-to-cloud)",
  },
  imageToJobSession: {
    composes: "$image",
    backgroundImage: "var(--galileo-assets-to-jobsession)",
  },
});

interface FormValues {
  jobSessionPath: string;
  remoteStoragePath: string;
}
const initialValues: FormValues = {
  jobSessionPath: "",
  remoteStoragePath: "",
};

interface ISelectedFile {
  fileName: string;
  storage: PathSelectInputType;
}

type Props = {
  onShowFileDialog: (options: OpenFileDialogProps) => Promise<URI | undefined>;
  onShowAlert: (message: string) => void;
  getIsPathFile: (path: string) => Promise<boolean>;
};

const CopyActionScreen = (props: Props) => {
  const { onShowFileDialog, getIsPathFile } = props;
  const { setCurrentScreen } = useStorjWidgetContext();
  const [sourcePath, setSourcePath] = useState<string>("");
  const [selectedFile, setSelectedFile] = useState<ISelectedFile | null>(null);
  const [direction, setDirection] = useState<SyncActionDirection | null>(null);
  const [destinationPath, setDestinationPath] = useState<string>("");
  const [toJobSessionHovered, setToJobSessionHovered] =
    useState<boolean>(false);
  const [toCloudHovered, setToCloudHovered] = useState<boolean>(false);
  const [isFileSelectorModalOpen, setIsFileSelectorModalOpen] =
    useState<boolean>(false);
  const classes = useStyles();
  const commonClasses = useCommonStyles();
  const selectedRemoteName = localStorage.getItem(
    LocalStorageKey.SELECTED_REMOTE
  );
  const handleSubmit = async (
    values: FormValues,
    helpers: FormikHelpers<FormValues>
  ) => {
    const { setSubmitting, setFieldError } = helpers;
    console.log(JSON.stringify(values));
    setSubmitting(true);
    if (
      selectedFile?.storage === PathSelectInputType.REMOTE_STORAGE &&
      direction === SyncActionDirection.JOB_TO_REMOTE
    ) {
      setFieldError("remoteStoragePath", destinationFileErrorMessage);
      return;
    }
    if (
      selectedFile?.storage === PathSelectInputType.JOB_SESSION &&
      direction === SyncActionDirection.REMOTE_TO_JOB
    ) {
      setFieldError("jobSessionPath", destinationFileErrorMessage);
      return;
    }
    const options = {
      body: JSON.stringify({
        srcFs:
          selectedFile && sourcePath.includes(selectedFile.fileName)
            ? removeFileNameFromPath(sourcePath)
            : sourcePath,
        dstFs:
          selectedFile && destinationPath.includes(selectedFile.fileName)
            ? removeFileNameFromPath(destinationPath)
            : destinationPath,
        ...(selectedFile && { srcRemote: selectedFile.fileName }),
        ...(selectedFile && { dstRemote: selectedFile.fileName }),
        _async: true,
      }),
    };
    let operation = RCloneEndPoints.copyDir;
    if (selectedFile) {
      operation = RCloneEndPoints.copyFile;
    }
    try {
      const res = await fetchRClone(operation, options);
      const json = await res.json();
      const newJob = json.jobid;
      console.log("response: ", json);
      saveJobsToStorage(
        newJob,
        sourcePath,
        destinationPath,
        LocalStorageKey.JOBS_COPY
      );
      setCurrentScreen(EScreenView.JOB_STATUS_SCREEN);
    } catch (error) {
      console.error(error);
      setFieldError(
        "jobSessionPath",
        "Something went wrong while doing copying. Please try again."
      );
      console.error(error);
    } finally {
      setSubmitting(false);
    }
  };

  const handleClickJobList = () => {
    setCurrentScreen(EScreenView.JOB_LIST_SCREEN);
  };

  const handleClickFileSelect = async (
    type: PathSelectInputType,
    setFieldValue: any
  ) => {
    if (type === PathSelectInputType.JOB_SESSION) {
      const result = await onShowFileDialog({
        title: "Select a Path",
        canSelectFolders: true,
        canSelectFiles: !selectedFile,
        openLabel: "Select Path",
      });
      if (result?.path.toString()) {
        const isFile = await getIsPathFile(result?.path.toString());
        if (isFile) {
          setSelectedFile({
            fileName: result?.path.base,
            storage: PathSelectInputType.JOB_SESSION,
          });
        } else {
          if (selectedFile?.storage === PathSelectInputType.JOB_SESSION) {
            setSelectedFile(null);
          }
        }
        setFieldValue("jobSessionPath", result?.path.toString());
      }
    } else if (type === PathSelectInputType.REMOTE_STORAGE) {
      setIsFileSelectorModalOpen(true);
    }
  };

  const handleClickStartSync = async (
    direction: SyncActionDirection,
    values: FormValues
  ) => {
    setDirection(direction);
    if (direction === SyncActionDirection.JOB_TO_REMOTE) {
      setSourcePath(values.jobSessionPath);
      setDestinationPath(values.remoteStoragePath);
    } else if (direction === SyncActionDirection.REMOTE_TO_JOB) {
      setSourcePath(values.remoteStoragePath);
      setDestinationPath(values.jobSessionPath);
    }
  };

  const handleClickConfirm = (
    selectedPath: string,
    selectedFileArg: string,
    setFieldValue: any
  ) => {
    if (selectedPath) {
      setFieldValue("remoteStoragePath", selectedPath);
    }
    if (selectedFileArg) {
      setSelectedFile({
        fileName: selectedFileArg,
        storage: PathSelectInputType.REMOTE_STORAGE,
      });
    } else {
      if (selectedFile?.storage === PathSelectInputType.REMOTE_STORAGE) {
        setSelectedFile(null);
      }
    }
  };

  return (
    <>
      <Formik
        initialValues={initialValues}
        onSubmit={handleSubmit}
        validationSchema={AccessGrantValidationSchema}
      >
        {({
          isSubmitting,
          values,
          handleChange,
          submitForm,
          setFieldValue,
        }) => (
          <Form className={commonClasses.form}>
            <div className={classes.actionContainer}>
              <BackButton />
              <h4
                onClick={handleClickJobList}
                className={commonClasses.linkAction}
              >
                Job List
              </h4>
            </div>
            <h3 style={{ marginTop: 0 }}>{selectedRemoteName}</h3>

            <PathSelectInput
              onClickFileSelect={() =>
                handleClickFileSelect(
                  PathSelectInputType.REMOTE_STORAGE,
                  setFieldValue
                )
              }
              label="Remote Storage Path*"
              onChange={handleChange}
              inputName="remoteStoragePath"
              placeholder="Click to choose the Remote Storage path"
              value={values.remoteStoragePath}
            />

            <PathSelectInput
              onClickFileSelect={() =>
                handleClickFileSelect(
                  PathSelectInputType.JOB_SESSION,
                  setFieldValue
                )
              }
              label="Job Session Path*"
              onChange={handleChange}
              inputName="jobSessionPath"
              placeholder="Click to choose the Job Session path"
              value={values.jobSessionPath}
            />

            <button
              type="button"
              style={{ marginBottom: 24 }}
              onMouseEnter={() => setToCloudHovered(true)}
              onMouseLeave={() => setToCloudHovered(false)}
              className={`theia-button primary ${commonClasses.button}`}
              disabled={isSubmitting}
              onClick={() => {
                submitForm();
                handleClickStartSync(SyncActionDirection.JOB_TO_REMOTE, values);
              }}
            >
              COPY JOB SESSION TO REMOTE STORAGE
              {isSubmitting && (
                <i
                  style={{ marginLeft: 8 }}
                  className="fa fa-spinner fa-spin"
                />
              )}
            </button>
            <button
              type="button"
              onMouseEnter={() => setToJobSessionHovered(true)}
              onMouseLeave={() => setToJobSessionHovered(false)}
              className={`theia-button primary ${commonClasses.button}`}
              disabled={isSubmitting}
              onClick={() => {
                submitForm();
                handleClickStartSync(SyncActionDirection.REMOTE_TO_JOB, values);
              }}
            >
              COPY REMOTE STORAGE TO JOB SESSION
              {isSubmitting && (
                <i
                  style={{ marginLeft: 8 }}
                  className="fa fa-spinner fa-spin"
                />
              )}
            </button>
            <div
              className={`${classes.image} ${
                toCloudHovered ? classes.imageToCloud : ""
              } ${toJobSessionHovered ? classes.imageToJobSession : ""}`}
            ></div>
            <RemotePathSelectorModal
              isOpen={isFileSelectorModalOpen}
              onClickConfirm={(selectedPath: string, selectedFile: string) =>
                handleClickConfirm(selectedPath, selectedFile, setFieldValue)
              }
              onClose={() => setIsFileSelectorModalOpen(false)}
              canSelectFiles={!selectedFile}
            />
          </Form>
        )}
      </Formik>
    </>
  );
};

export default CopyActionScreen;
