import { Constants } from './contants'
import getFilemd5sum from './utils'

function FileFactory(file) {
  this.offset = 0; //用于断点续传,默认为 0
  this.BYTES_PER_CHUNK = 1024 * 1024
  this.file = file
  this.fileSize = file.size
  this.fileType = (file.name.split('.')[1]).toLowerCase()
  this.chunkNum = this.BYTES_PER_CHUNK > this.fileSize ? Math.ceil(this.fileSize / this.BYTES_PER_CHUNK) : 1
  this.chunkSize = this.BYTES_PER_CHUNK > this.fileSize ? this.fileSize : this.BYTES_PER_CHUNK
}

FileFactory.prototype.setOffset = function (offset) {
  this.offset = offset
}

export default function UploadSdk(host, origin, token, file) {

  this.handlers = [] //用于处理出触发事件
  this.host = host.indexOf('http:') > -1 ? 'http:'+ host: host
  this.origin = origin
  this.token = token
  this.file = file

  this.generateMd5 = function (callback) {
    getFilemd5sum(this.file).then(result => {
      callback(result)
    })
  }

  this.imageUploadAction = function () {
    return new Promise((resolve, reject) => {
      let fileFactory = new FileFactory(this.file)
      if (!fileFactory.fileType.match('[(jpg)|(png)|(gif)]+$')) {
        reject(Constants.IMAGE_TYPE_ERROR)
      }
      this.generateMd5((md5) => {
        this.md5 = md5
        this.postImage(this.md5, fileFactory).then(res => {
          resolve(res)
        }).catch((err) => {
          reject(err)
        })
      })
    })
  }

  this.videoUploadAction = function () {
    return new Promise((resolve, reject) => {
      if (!this.file.type.match('[(mp4)|(rmvb)|(flv)|(mpeg)|(avi)]+$')) {
        reject(Constants.VIDOE_TYPE_ERROR)
      }
      this.postVideo().then(res => {
        resolve(res)
      }).catch((err) => {
        reject(err)
      })
    })
  }

  this.postVideo = function () {
    const self = this
    return new Promise((resolve, reject) => {
      let xhr = new XMLHttpRequest()
      xhr.open('POST', this.host + Constants.VIDEO_MULTIPART + this.origin, true)
      xhr.withCredentials = true;
      xhr.setRequestHeader('Authorization', `Bearer ${this.token}`)
      xhr.setRequestHeader('Content-type', 'application/json')
      xhr.upload.addEventListener("progress", function updateProgress(oEvent) {
        if (oEvent.lengthComputable) {
          let percentComplete = oEvent.loaded / oEvent.total * 100;
          self.emitUpdateProgress(percentComplete)
        }
      }, false)
      let fd = new FormData()
      fd.append('file', this.file)
      fd.append('code_rate', 'ld,sd,hd')
      xhr.send(fd)
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          let obj = JSON.parse(xhr.responseText)
          if (xhr.status === 304 || (xhr.status >= 200 && xhr.status < 300)) {
            resolve({
              code: Constants.UPLOAD_SUCCESS_CODE,
              url: obj.url,
              msg: 'success'
            })
          } else {
            reject({
              code: Constants.UPLOAD_FAILED_CODE,
              url: '',
              msg: obj.message
            })
          }
        }
      }
    })
  }

  this.postImage = function (md5, fileFactory) {
    const self = this
    return new Promise((resolve, reject) => {
      let xhr = new XMLHttpRequest()
      xhr.upload.addEventListener("progress", function updateProgress(oEvent) {
        if (oEvent.lengthComputable) {
          let percentComplete = oEvent.loaded / oEvent.total * 100;
          self.emitUpdateProgress(percentComplete)
        }
      }, false)
      xhr.open('POSt', this.host + Constants.IMAGE_MULTIPART + this.origin, true)
      xhr.withCredentials = true
      xhr.setRequestHeader('Authorization', `Bearer ${this.token}`)
      xhr.setRequestHeader('X-Upload-File-Size', fileFactory.fileSize)
      xhr.setRequestHeader('X-Upload-Chunk-Index', 1 + '')
      xhr.setRequestHeader('X-Upload-Chunk-Num', fileFactory.chunkNum)
      xhr.setRequestHeader('X-Upload-Chunk-Size', fileFactory.chunkSize)
      xhr.setRequestHeader('X-Upload-Offset', fileFactory.offset + '')
      xhr.setRequestHeader('X-Upload-File-Md5', md5)
      xhr.setRequestHeader('X-Upload-File-Type', fileFactory.fileType)
      let fd = new FormData()
      fd.append('file', this.file)
      xhr.send(fd)
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          let obj = JSON.parse(xhr.responseText)
          if (xhr.status === 304 || (xhr.status >= 200 && xhr.status < 300)) {

            if (obj.status === 1) {
              resolve({
                code: Constants.UPLOAD_SUCCESS_CODE,
                url: obj.url,
                msg: 'success'
              })
            } else if (obj.status === 0) {
              fileFactory.setOffset(obj.msg)
              this.getAllResponseHeaders.postImage(md5, fileFactory)
            }
          } else {
            reject({
              code: Constants.UPLOAD_FAILED_CODE,
              url: '',
              msg: obj.message
            })
          }
        }
      }
    })
  }
}

UploadSdk.prototype = {

  onUpdateProgress: function(subscriber){
    let isExist = this.handlers.some(function(item){
      return item == subscriber;
    })
    if(!isExist){
      this.handlers.push(subscriber);
    }
    return this;
  },
  
  emitUpdateProgress: function(data){
    this.handlers.forEach(function(fn){
      fn(data)
    })
    return this;
  }
}