import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import { Icon } from '@pubsweet/ui'
import { DropTarget } from 'react-dnd'
import { NativeTypes } from 'react-dnd-html5-backend'
import { compose, getContext, withHandlers, withState } from 'recompose'
import {
  SortableList,
  Spinner,
} from 'pubsweet-components-faraday/src/components'

import FileItem from './FileItem'
import FilePicker from './FilePicker'
import FileDropzone from './FileDropzone'
import classes from './FileSection.local.scss'

const DragHandle = () => (
  <div className={classnames(classes['drag-handle'])}>
    <Icon size={14}>chevron_up</Icon>
    <Icon size={10}>menu</Icon>
    <Icon size={14}>chevron_down</Icon>
  </div>
)

const FileSection = ({
  error,
  title,
  files,
  listId,
  isOver,
  isLast,
  isFirst,
  addFile,
  canDrop,
  moveItem,
  isFileOver,
  removeFile,
  connectFileDrop,
  connectDropTarget,
  allowedFileExtensions,
  isFetching,
  canDropFile,
  disabledFilepicker,
  dropSortableFile,
  previewFile,
}) =>
  connectFileDrop(
    connectDropTarget(
      <div
        className={classnames({
          [classes['drop-section']]: true,
          [classes['no-border-top']]: !isFirst,
          [classes['dashed-border']]: !isLast,
          [classes['is-over']]: isFileOver || (isOver && canDrop),
        })}
      >
        <div className={classnames(classes.header)}>
          <div className={classnames(classes['picker-container'])}>
            <span className={classnames(classes.title)}>{title}</span>
            {!isFetching[listId] ? (
              <FilePicker
                allowedFileExtensions={allowedFileExtensions}
                disabled={disabledFilepicker()}
                onUpload={addFile}
              >
                <div
                  className={classnames({
                    [classes['upload-button']]: true,
                    [classes['disabled-picker']]: disabledFilepicker(),
                  })}
                >
                  <Icon color={disabledFilepicker() ? '#999' : '#333'}>
                    file-plus
                  </Icon>
                </div>
              </FilePicker>
            ) : (
              <Spinner />
            )}
          </div>
          <span className={classnames(classes.error)}>{error}</span>
        </div>
        <SortableList
          beginDragProps={['id', 'index', 'name', 'listId']}
          dragHandle={DragHandle}
          dropItem={dropSortableFile}
          items={files}
          listId={listId}
          listItem={FileItem}
          moveItem={moveItem}
          previewFile={previewFile}
          removeFile={removeFile}
        />
        <FileDropzone label="Drag files here or use the add button." />
      </div>,
    ),
  )

export default compose(
  getContext({
    isFetching: PropTypes.object,
  }),
  withState('error', 'setError', ''),
  withHandlers({
    clearError: ({ setError }) => () => {
      setError(e => '')
    },
  }),
  withHandlers({
    setError: ({ setError, clearError }) => err => {
      setError(e => err, () => setTimeout(clearError, 3000))
    },
    disabledFilepicker: ({ files, maxFiles }) => () => files.length >= maxFiles,
  }),
  DropTarget(
    'item',
    {
      drop(
        {
          changeList,
          listId: toListId,
          maxFiles,
          files,
          setError,
          allowedFileExtensions,
          ...pm
        },
        monitor,
      ) {
        const { listId: fromListId, id, name } = monitor.getItem()
        const fileExtention = name.split('.')[1]

        if (
          allowedFileExtensions &&
          !allowedFileExtensions.includes(fileExtention)
        ) {
          setError('Invalid file type.')
          return
        }

        if (files.length >= maxFiles) {
          setError('No more files can be added to this section.')
          return
        }

        if (toListId === fromListId) return
        changeList(fromListId, toListId, id)
      },
      canDrop({ listId: toListId, setError }, monitor) {
        const { listId: fromListId } = monitor.getItem()
        return toListId !== fromListId
      },
    },
    (connect, monitor) => ({
      connectDropTarget: connect.dropTarget(),
      isOver: monitor.isOver(),
      canDrop: monitor.canDrop(),
    }),
  ),
  DropTarget(
    NativeTypes.FILE,
    {
      drop(
        { files, maxFiles, addFile, allowedFileExtensions, setError },
        monitor,
      ) {
        const [file] = monitor.getItem().files
        const fileExtention = file.name.split('.')[1]

        if (files.length >= maxFiles) {
          setError('No more files can be added to this section.')
          return
        }

        if (
          allowedFileExtensions &&
          allowedFileExtensions.includes(fileExtention)
        ) {
          addFile(file)
        } else {
          setError('Invalid file type.')
        }
      },
    },
    (connect, monitor) => ({
      connectFileDrop: connect.dropTarget(),
      isFileOver: monitor.isOver(),
      canDropFile: monitor.canDrop(),
    }),
  ),
)(FileSection)