import { useState, useCallback } from 'react'
import styled from 'styled-components'
import { Dropzone } from './dropzone'
import type { DropzoneFileRejection, DropzoneState, DropzoneFileError } from './dropzone'
import readme from './dropzone.readme.md'

export default {
  title: 'General/Dropzone',
  component: Dropzone,
  parameters: {
    readme: {
      content: readme,
    },
  },
}

const DropArea = styled.div`
  text-align: center;
  width: 80%;
  padding: 40px 20px;
  border: 1px dashed gray;
`

const ErrorMessage = styled.p`
  color: red;
  font-size: 14px;
`

const DropAreaComponent = (text?: string) => () => (
  <DropArea>
    <p>Drag 'n' drop some files here, or click to select files</p>
    {text && <em>{text}</em>}
  </DropArea>
)

const Template = ({ children, ...restArgs }) => {
  const [files, setFiles] = useState<File[]>([])
  const [rejections, setRejections] = useState<DropzoneFileRejection[]>([])

  const onDrop = useCallback(
    (acceptedFiles: File[], fileRejections: DropzoneFileRejection[]) => {
      setFiles((oldFiles) => [...oldFiles, ...acceptedFiles])
      setRejections(fileRejections)
    },
    [setFiles, setRejections]
  )

  const acceptedFileList = () => (
    <>
      <h4>Files</h4>
      <ul>
        {files.map((file, index) => (
          <li key={index}>
            {file.name} - {file.size} bytes
          </li>
        ))}
      </ul>
    </>
  )

  const rejectedFileList = () => (
    <>
      <h4>Rejected files</h4>
      <ul>
        {rejections.map(({ file, errors }, index) => (
          <li key={index}>
            {file.name} - {file.size} bytes
            {errors.map((e) => (
              <ErrorMessage key={e.code}>{e.message}</ErrorMessage>
            ))}
          </li>
        ))}
      </ul>
    </>
  )

  return (
    <div>
      <Dropzone {...restArgs} onDrop={onDrop}>
        {children}
      </Dropzone>
      <aside>
        {acceptedFileList()}
        {rejections.length > 0 && rejectedFileList()}
      </aside>
    </div>
  )
}

export const Basic = Template.bind({})
Basic.args = {
  children: DropAreaComponent(),
}

export const SpecificFileTypes = Template.bind({})
SpecificFileTypes.args = {
  children: DropAreaComponent('(Only *.jpeg images will be accepted)'),
  accept: {
    'image/jpeg': [],
  },
}

export const SpecificFileNumbers = Template.bind({})
SpecificFileNumbers.args = {
  children: DropAreaComponent('(2 files are the maximum number of files you can drop here)'),
  maxFiles: 2,
}

const UploadButton = ({ open }: DropzoneState) => {
  return <button onClick={open}>Upload file</button>
}

export const OpenFileDialog = Template.bind({})
OpenFileDialog.args = {
  children: UploadButton,
  noDrag: true,
  noClick: true,
  noKeyboard: true,
}

const maxLength = 10
const nameLengthValidator = (file: File): DropzoneFileError | void => {
  if (file.name.length <= maxLength) {
    return
  }

  return {
    code: 'name-too-large',
    message: `Name is larger than ${maxLength} characters`,
  }
}
export const CustomValidation = Template.bind({})
CustomValidation.args = {
  children: DropAreaComponent('(File name must LESS than 10 characters)'),
  validator: nameLengthValidator,
}
