import React, { ReactElement, useRef, MutableRefObject, useState } from 'react'
import styles from './index.module.css'
import List from '../List'
import Item from './Item'
import { UPREADY, UPSUCCESS, UPING, UPERR} from './constant'
import http from '../../http'


async function uploadFile({ url, file, body, cb, check }: { url: string, file: Array<File> | File, body: any, cb: Function, check?: string}) {
  let form = new FormData()

  if (file instanceof Array) {
    file.forEach(f => form.append('file', f))
  } else {
    form.append('file', file)
  }

  Object.keys(body).forEach((k: string) => {
    form.append(k, body[k])
  })

  try {
    if (check) {
      let res = await http.get(check)
      if (res.data.status !== 200) {
        alert(res.data.message)
        return cb(0, true)
      }
    }


    let res = await http({
      url: url,
      method: 'POST',
      data: form,
      onUploadProgress(ev) {
        let step = (ev.loaded / ev.total) * 100
        if (step !== 100) cb(step)
      },
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    })
    if (res.data.status !== 200) {
      alert(res.data.message)
      cb(0, true)  
    } else {
      cb(100)
    }
  } catch(e) {
    cb(0, true)
  }
}

interface ItemCtrlProps extends UFile {
  api: string,
  handleUpSuccess: Function,
  multiple?: boolean,
  body: Object,
  check?: string,
  closeHandle: Function
}

function ItemCtrl(props: ItemCtrlProps) : ReactElement {
  const [status, setStatus] = useState(UPREADY)
  const [percentage, setPercentage] = useState(status === UPREADY ? 0 : 100)
  if (status === UPREADY) {
    setStatus(UPING)
    uploadFile({
      file: props.multiple ? props.file : props.file[0],
      url: props.api,
      body: props.body,
      check: props.check && (props.check + props.name + '/'),
      cb(speed: number, err?: boolean) {
        setPercentage(speed)
        if (speed === 100) {
          setStatus(UPSUCCESS)
          props.handleUpSuccess()
        } else if (err) {
          setStatus(UPERR)
        }
      }
    })
  }
  
  return <Item {...props} status={status} percentage={percentage} closeHandle={props.closeHandle} />
}

interface UploadProps {
  multiple?: boolean,
  className?: string,
  api: string,
  upHandle: Function,
  body?: Object | null,
  check?: string,
  filter?: Function
}

function Upload(props: UploadProps) : ReactElement {
  let [flist, setFlist] = useState<Array<UFile>>([])
  const inputfile = (useRef(null) as MutableRefObject<any>)
  const onClickHandle = () => inputfile.current.click()
  const onChangeHandle = async () => {
    let files = [...inputfile.current.files]
    if (files.length === 0) return;
    let newFiles = await Promise.all(
      files.map(async (file: File) => ({
        name: file.name,
        size: file.size,
        file: file
      }))
    );

    if (props.filter) {
      let ret = props.filter(props.multiple ? files : files[0])
      if (!ret.accord) {
        inputfile.current.value = null
        alert(ret.msg)
        return false;
      }
    }

    for (let i = 0; i < newFiles.length; i++) {
      if (escape(newFiles[i].name).indexOf("%u") >= 0) {
        inputfile.current.value = null
        alert("上传文件文件名不能包含中文！");
        return false;
      }
    }
    let newFile = {
      name: newFiles.map(f => f.name).join(' + '),
      size: newFiles.reduce((previous, current) => previous + current.size, 0),
      file: newFiles.map(f => f.file)
    }
    setFlist([])
    setTimeout(() => setFlist([newFile]), 500)
    inputfile.current.value = null
  }

  const closeHandle = (file:any) => {
    let fl = [...flist]
    fl.splice(fl.indexOf(file), 1)
    setFlist(fl)
  }

  return (
    <div className={props.className}>
      <div className={styles.filebutton}>
        <input type="file" ref={inputfile} multiple={props.multiple} onChange={onChangeHandle}/>
        <span onClick={onClickHandle}>点击上传</span>
      </div>
      <List data={flist} className="uplist">
        {(file: UFile, i: number, s: string) => (
          <ItemCtrl
            closeHandle={() => closeHandle(file) }
            handleUpSuccess={props.upHandle}
            body={props.body ? props.body: {}}
            api={props.api} {...file}
            multiple={props.multiple}
            check={props.check}
            key={i} />
        )}
      </List>
    </div>
  )
}

export default Upload