import React, { Fragment } from 'react'
import { th } from '@pubsweet/ui'
import PropTypes from 'prop-types'
import { get, isEqual } from 'lodash'
import { connect } from 'react-redux'
import styled from 'styled-components'
import { withRouter } from 'react-router-dom'
import { change as changeForm } from 'redux-form'
import { selectCurrentVersion } from 'xpub-selectors'
import {
  compose,
  lifecycle,
  withState,
  getContext,
  withContext,
  withHandlers,
} from 'recompose'
import { SortableList } from 'pubsweet-components-faraday/src/components'
import { isRevisionFlow } from 'pubsweet-component-wizard/src/redux/conversion'

import FileSection from './FileSection'
import {
  uploadFile,
  deleteFile,
  getFileError,
  getRequestStatus,
} from '../../redux/files'

const Files = ({
  files,
  error,
  addFile,
  moveItem,
  removeFile,
  changeList,
  isRevisionFlow,
  dropSortableFile,
}) => (
  <Fragment>
    <Error show={error}> File error, please try again.</Error>
    <FileSection
      addFile={addFile('manuscripts')}
      allowedFileExtensions={['pdf', 'doc', 'docx']}
      changeList={changeList}
      dropSortableFile={dropSortableFile}
      files={get(files, 'manuscripts') || []}
      isFirst
      listId="manuscripts"
      maxFiles={Number.POSITIVE_INFINITY}
      moveItem={moveItem('manuscripts')}
      removeFile={removeFile('manuscripts')}
      title="Main manuscript"
    />
    <FileSection
      addFile={addFile('supplementary')}
      changeList={changeList}
      dropSortableFile={dropSortableFile}
      files={get(files, 'supplementary') || []}
      listId="supplementary"
      maxFiles={Number.POSITIVE_INFINITY}
      moveItem={moveItem('supplementary')}
      removeFile={removeFile('supplementary')}
      title="Supplementarry files"
    />
    <FileSection
      addFile={addFile('coverLetter')}
      allowedFileExtensions={['pdf', 'doc', 'docx']}
      changeList={changeList}
      dropSortableFile={dropSortableFile}
      files={get(files, 'coverLetter') || []}
      isLast={!isRevisionFlow}
      listId="coverLetter"
      maxFiles={1}
      moveItem={moveItem('coverLetter')}
      removeFile={removeFile('coverLetter')}
      title="Cover letter"
    />
    {isRevisionFlow && (
      <FileSection
        addFile={addFile('responseToReviewers')}
        allowedFileExtensions={['pdf', 'doc', 'docx']}
        changeList={changeList}
        dropSortableFile={dropSortableFile}
        files={get(files, 'responseToReviewers') || []}
        isLast={isRevisionFlow}
        listId="responseToReviewer"
        maxFiles={1}
        moveItem={moveItem('responseToReviewers')}
        removeFile={removeFile('responseToReviewers')}
        title="Response to reviewers"
      />
    )}
  </Fragment>
)

export default compose(
  getContext({
    project: PropTypes.object,
    version: PropTypes.object,
  }),
  withRouter,
  connect(
    (state, { project, version }) => ({
      error: getFileError(state),
      isFetching: getRequestStatus(state),
      version: selectCurrentVersion(state, project),
      isRevisionFlow: isRevisionFlow(state, project, version),
    }),
    {
      changeForm,
      uploadFile,
      deleteFile,
    },
  ),
  withState('files', 'setFiles', {
    manuscripts: [],
    coverLetter: [],
    supplementary: [],
    responseToReviewers: [],
  }),
  lifecycle({
    componentDidMount() {
      const { version, setFiles, filePath = 'files' } = this.props
      setFiles(prev => ({
        manuscripts: get(version, `${filePath}.manuscripts`) || [],
        coverLetter: get(version, `${filePath}.coverLetter`) || [],
        supplementary: get(version, `${filePath}.supplementary`) || [],
        responseToReviewers:
          get(version, `${filePath}.responseToReviewers`) || [],
      }))
    },
    componentWillReceiveProps(nextProps) {
      const { setFiles, version, filePath = 'files' } = this.props
      const { version: newVersion } = nextProps

      const files = get(newVersion, filePath)
      const previousFiles = get(version, filePath)

      if (!isEqual(previousFiles, files)) {
        setFiles(files)
      }
    },
  }),
  withHandlers({
    dropSortableFile: ({
      files,
      setFiles,
      changeForm,
      parentForm = 'wizard',
    }) => (otherProps, dragProps) => {
      // do something if the file is not changing list
      const { listId: fromListId } = otherProps
      const { listId: toListId } = dragProps
      if (fromListId === toListId) {
        setFiles(files)
        changeForm(parentForm, 'files', files)
      }
    },
    changeList: ({ files, setFiles, changeForm, parentForm = 'wizard' }) => (
      fromListId,
      toListId,
      id,
    ) => {
      const swappedFile = files[fromListId].find(f => f.id === id)

      const fromFiles = files[fromListId].filter(f => f.id !== id)
      const toFiles = [...files[toListId], swappedFile]

      const newFiles = {
        ...files,
        [toListId]: toFiles,
        [fromListId]: fromFiles,
      }
      setFiles(newFiles)
      changeForm(parentForm, 'files', newFiles)
    },
    addFile: ({
      files,
      version,
      setFiles,
      uploadFile,
      changeForm,
      parentForm = 'wizard',
    }) => type => file => {
      uploadFile(file, type, version.id)
        .then(file => {
          const newFiles = {
            ...files,
            [type]: [...files[type], file],
          }
          setFiles(newFiles)
          changeForm(parentForm, 'files', newFiles)
        })
        .catch(e => console.error(`Couldn't upload file.`, e))
    },
    moveItem: ({ moveFiles, files, setFiles }) => type => (
      dragIndex,
      hoverIndex,
    ) => {
      const newFiles = {
        ...files,
        [type]: SortableList.moveItem(files[type], dragIndex, hoverIndex),
      }
      setFiles(newFiles)
    },
    removeFile: ({
      files,
      version,
      setFiles,
      changeForm,
      deleteFile,
      parentForm = 'wizard',
    }) => type => id => e => {
      e.preventDefault()
      deleteFile(id, type)
        .then(() => {
          const newFiles = {
            ...files,
            [type]: files[type].filter(f => f.id !== id),
          }
          setFiles(newFiles)
          changeForm(parentForm, 'files', newFiles)
        })
        .catch(e => console.error(`Couldn't delete file.`, e))
    },
  }),
  withContext(
    {
      isFetching: PropTypes.object,
    },
    ({ isFetching }) => ({
      isFetching,
    }),
  ),
)(Files)

// #region styles
const Error = styled.div`
  color: firebrick;
  display: flex;
  justify-content: flex-end;
  margin: ${th('subGridUnit')} 0;
  opacity: ${({ show }) => (show ? 1 : 0)};
`
// #endregion