import React, {useEffect, useState} from 'react';
import {
  lightErrorColor,
  primary,
  primary15,
  primary45,
  primary5,
} from '../utils/colors';
import {FiDownload, FiEdit, FiShare2, FiTrash} from 'react-icons/fi';
import {FaFolderOpen} from 'react-icons/fa';
import useHover from '../hooks/useHover';
import {ToolItem} from './ToolItem';
import {FilePreview} from './FilePreview';
import {
  getBlobFromPath,
  filenameExt,
  getFileInfoFromCID,
  getFileTime,
  getIconForPath,
  humanFileSize,
  getPercent,
  isFileExtensionAudio,
  hasMouse,
  getEncryptionInfoFromFilename,
  doesUserHaveWriteInInstance,
} from '../utils/Utils';
import {saveAs} from 'file-saver';
import useTextInput from '../hooks/useTextInput';
import {useDispatch} from 'react-redux';
import {setShareData, setStatus} from '../actions/tempData';
import useDoubleClick from '../hooks/useDoubleClick';
import {useIsSmallScreen} from '../hooks/useIsSmallScreen';
import {contextMenu} from 'react-contexify';
import {MobileActionsDialog} from './MobileActionsDialog';

export function FileItem({
  data,
  sharedFs,
  setCurrentDirectory,
  ipfs,
  isParent,
  snapshot,
  forceIcon,
  onIconClicked,
  readOnly,
}) {
  const {path, type} = data;
  const pathSplit = path.split('/');
  const name = pathSplit[pathSplit.length - 1];
  const mtime = sharedFs && sharedFs.current.fs.read(path)?.mtime;
  const [hoverRef, isHovered] = useHover();
  const [CID, setCID] = useState(null);
  const [fileInfo, setFileInfo] = useState(null);
  const [editMode, setEditMode] = useState(false);
  const [mobileActionsVisible, setMobileActionsVisible] = useState(false);
  const [fileBlob, setFileBlob] = useState(null);
  const [doubleClickRef] = useDoubleClick(() => setEditMode(true));
  const parentPath = pathSplit.slice(0, pathSplit.length - 1).join('/');
  const fileExtension = filenameExt(name);
  const isSmallScreen = useIsSmallScreen();
  const contextID = `menu-id`;
  const contextNoShareID = `menu-id-no-share`;
  const exists = sharedFs && sharedFs.current.fs.exists(path);
  const isTouchDevice = !hasMouse;
  const isUnsharable = sharedFs?.current.encrypted && type === 'dir';
  const hasWrite = sharedFs && doesUserHaveWriteInInstance(sharedFs.current);

  const styles = {
    paddingContainer: {
      paddingTop: 3,
      paddingBottom: 3,
    },
    outer: {
      borderRadius: 4,
      color: primary5,
      fontSize: 14,
      padding: 7,
      marginBottom: 8,
      fontFamily: 'Open Sans',
      userSelect: 'none',
    },
    container: {
      display: 'flex',
      flexDirection: 'row',
      flexWrap: isSmallScreen ? 'wrap' : 'nowrap',
      justifyContent: 'space-between',
      cursor: 'pointer',
    },
    flexItem: {
      width: '100%',
      display: 'flex',
      flexDirection: 'row',
      justifyContent: 'flex-start',
      alignItems: 'center',
      flexGrow: 2,
      marginBottom: isSmallScreen ? 10 : 0,
    },
    icon: {
      marginRight: 4,
      width: 30,
      flexShrink: 0,
    },
    tools: {
      display: isTouchDevice ? 'none' : 'flex',
      justifyContent: 'flex-end',
      width: '100%',
      opacity: (isHovered || fileBlob) && !isParent ? 1 : 0,
      pointerEvents: (isHovered || fileBlob) && !isParent ? null : 'none',
      fontSize: 14,
      marginLeft: 0,
    },
    filename: {
      textAlign: 'left',
      whiteSpace: 'nowrap',
      textOverflow: 'ellipsis',
      overflow: 'hidden',
    },
  };

  const dispatch = useDispatch();

  const InputComponent = useTextInput(
    editMode,
    (editNameValue) => rename(editNameValue),
    () => setEditMode(false),
    name,
    {
      placeholder: '',
    },
  );

  const iconComponent = forceIcon ? forceIcon : getIconForPath(type, name);

  const getCID = async () => {
    let tmpCID;

    if (data.cid) {
      tmpCID = data.cid;
    } else if (exists) {
      tmpCID = await sharedFs.current.read(path);
    }

    const tmpFileInfo = await getFileInfoFromCID(tmpCID, ipfs);

    setFileInfo(tmpFileInfo);
    setCID(tmpCID);
    return tmpCID;
  };

  useEffect(() => {
    if (exists && type !== 'dir') {
      getCID();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [path]);

  const IconComponent = iconComponent;

  const rename = async (editNameValue) => {
    try {
      dispatch(setStatus({message: 'Renaming file'}));
      await sharedFs.current.move(path, parentPath, editNameValue);
      dispatch(setStatus({}));
    } catch (e) {
      console.log('Error moving!', e);
    }
  };

  async function getBlob() {
    let blob;

    if (!fileBlob) {
      dispatch(setStatus({message: 'Fetching download'}));
      const handleUpdate = (currentIndex, totalCount) => {
        dispatch(
          setStatus({
            message: `[${getPercent(currentIndex, totalCount)}%] Downloading`,
          }),
        );
      };
      blob = await getBlobFromPath(sharedFs.current, path, handleUpdate);
      dispatch(setStatus({}));
    } else {
      blob = fileBlob;
    }
    return blob;
  }

  const saveAsFile = (blob, name) => {
    if (type === 'dir') {
      name = `${name}.zip`;
    }

    saveAs(blob, name);
  };

  const handleShare = () => {
    setMobileActionsVisible(false);

    dispatch(
      setShareData({
        name,
        CID,
        path,
        pathType: type,
      }),
    );
  };

  const handleDownload = async () => {
    setMobileActionsVisible(false);

    const blob = await getBlob();
    saveAsFile(blob, name);
  };

  const handleEdit = async () => {
    setMobileActionsVisible(false);

    setEditMode(true);
  };

  const handleDelete = async () => {
    setMobileActionsVisible(false);

    dispatch(
      setStatus({
        message: `Deleting ${type === 'dir' ? 'folder' : 'file'}`,
      }),
    );
    await sharedFs.current.remove(path);
    dispatch(setStatus({}));
  };

  const fetchPreview = async () => {
    // Only fetch for audio on click now
    if (!fileBlob && isFileExtensionAudio(fileExtension)) {
      dispatch(setStatus({message: 'Fetching preview'}));
      const blob = await getBlob();
      dispatch(setStatus({}));
      setFileBlob(blob);
    } else {
      setFileBlob(null);
    }
  };

  const handleClick = async (event) => {
    event.stopPropagation();

    if (isTouchDevice && type !== 'dir') {
      setMobileActionsVisible(true);

      return;
    }

    if (onIconClicked) {
      onIconClicked();
      return;
    }

    if (editMode) {
      return;
    }

    if (type === 'dir') {
      setCurrentDirectory(path);
    } else {
      await fetchPreview();
    }
  };

  let mobileActionItems = [
    {
      title: 'Download',
      onClick: handleDownload,
      iconComponent: FiDownload,
    },
  ];

  if (hasWrite) {
    mobileActionItems = mobileActionItems.concat([
      {
        title: 'Rename',
        onClick: handleEdit,
        iconComponent: FiEdit,
      },
      {
        title: 'Delete',
        onClick: handleDelete,
        iconComponent: FiTrash,
        forceColor: lightErrorColor,
      },
    ]);
  }

  if (!isUnsharable) {
    mobileActionItems.unshift({
      title: 'Share',
      onClick: handleShare,
      iconComponent: FiShare2,
    });
  }

  if (type === 'dir') {
    mobileActionItems.unshift({
      title: 'Open folder',
      onClick: () => setCurrentDirectory(path),
      iconComponent: FaFolderOpen,
    });
  } else {
    if ((!fileBlob && isFileExtensionAudio(fileExtension)) || onIconClicked) {
      mobileActionItems.unshift({
        title: 'Open preview',
        onClick: () => {
          setMobileActionsVisible(false);

          if (onIconClicked) {
            onIconClicked();
          } else {
            fetchPreview();
          }
        },
        iconComponent: iconComponent,
      });
    }
  }

  const getContent = () => {
    if (!snapshot) {
      snapshot = {};
    }

    return (
      <div
        ref={hoverRef}
        style={styles.paddingContainer}
        className={`fileItem`}>
        <MobileActionsDialog
          isVisible={mobileActionsVisible}
          name={name}
          fileIcon={iconComponent}
          onClose={() => setMobileActionsVisible(false)}
          items={mobileActionItems}
        />
        <div
          onContextMenu={(event) => {
            event.preventDefault();

            contextMenu.show({
              event,
              id: isUnsharable ? contextNoShareID : contextID,
              props: {
                handleDelete,
                handleDownload,
                handleShare,
                handleEdit,
              },
            });
          }}
          style={{
            ...styles.outer,
            backgroundColor:
              (isHovered ||
                fileBlob ||
                snapshot.isDragging ||
                (snapshot.combineTargetFor && type === 'dir')) &&
              !isTouchDevice
                ? primary15
                : '#FFF',
          }}>
          <div style={styles.container} onClick={handleClick}>
            <div
              style={{
                ...styles.flexItem,
                maxWidth: isSmallScreen ? null : '25%',
              }}>
              <IconComponent color={primary45} size={16} style={styles.icon} />
              {editMode ? (
                <>{InputComponent}</>
              ) : isParent ? (
                '. . /'
              ) : (
                <span ref={doubleClickRef} style={styles.filename}>
                  {name}
                </span>
              )}
            </div>
            <div style={{...styles.flexItem, justifyContent: 'flex-end'}}>
              {type !== 'dir' && fileInfo ? humanFileSize(fileInfo.size) : null}
            </div>
            <div style={{...styles.flexItem, justifyContent: 'flex-end'}}>
              {type !== 'dir' && (mtime || fileInfo?.mtime)
                ? getFileTime(mtime?.secs || fileInfo.mtime.secs)
                : null}
            </div>
            <div style={styles.tools}>
              <div>
                <ToolItem
                  id={`Share-${type}`}
                  iconComponent={FiShare2}
                  changeColor={primary}
                  tooltip={
                    isUnsharable ? 'No encrypted folder sharing yet!' : 'Share'
                  }
                  onClick={handleShare}
                  disabled={isUnsharable}
                />

                <ToolItem
                  id={`Download-${type}`}
                  iconComponent={FiDownload}
                  changeColor={primary}
                  tooltip={'Download'}
                  onClick={handleDownload}
                />

                {!readOnly && hasWrite ? (
                  <>
                    <ToolItem
                      id={`Rename-${type}`}
                      iconComponent={FiEdit}
                      changeColor={primary}
                      tooltip={'Rename'}
                      onClick={handleEdit}
                    />
                    <ToolItem
                      id={`Delete-${type}`}
                      iconComponent={FiTrash}
                      tooltip={'Delete'}
                      onClick={handleDelete}
                    />
                  </>
                ) : null}
              </div>
            </div>
          </div>
          {fileBlob ? (
            <div style={styles.preview}>
              <FilePreview blob={fileBlob} filename={name} />
            </div>
          ) : null}
        </div>
      </div>
    );
  };

  return <>{getContent()}</>;
}