/* eslint-disable babel/no-unused-expressions */
/* eslint-disable @lwc/lwc/no-async-await */
/**
 *
 * RangeDownloader.js by Zapic @ 2021
 * https://github.com/KawaiiZapic/RangeDownloader-js/
 *
 * Please DO NOT remove this copyright message, as the basic respect for original author.
 *
 */
import axios from '@/common/services/axios-instance'
var RangeDownloader = (function() {
  var RangeDownloader = function(param) {
    this.url = param.url || null
    this.fileSize = param.fileSize
    this.db = param.db
    this.name = param.name
    if (!this.url) {
      throw Error('Invaild url.')
    }
    this.onerror = param.onerror || null
    this.onload = param.onload || null
    this.oncancle = param.oncancle || null
    this.onprogress = param.onprogress || null
    this.chucks = []
    this.Authorization = param.Authorization || null
  }
  RangeDownloader.prototype.start = function() {
    if (this.loaded) {
      return
    }
    var _self = this
    const maxThread = 2
    this.abortController = new AbortController()
    const modulejx = function(url, j, c, cc) {
      if (url) {
        _self.db.attachmentShardingBlob.get(_self.name + j).then((b) => {
          if (!b) {
            c.setIndex(j)
            c.download(cc)
          } else {
            cc.continue()
            _self.downloadedSize += b.blob.size
          }
        })
      }
    }
    const module = function(url, r, i, b, abortController, c, cc) {
      if (url) {
        try {
          fetch(url, {
            method: 'get',
            responseType: 'blob',
            headers: {
              Range: 'bytes=' + r,
            },
            signal: abortController.signal,
          })
            .then(function(resp) {
              _self.running = true
              if (resp.status === 400) {
                throw new Error(`status: 400; ${resp.statusText}`)
              } else {
                _self.supportPartial = resp.status === 206
                _self.totalSize = parseInt(resp.headers.get('Content-Length'))
                _self.totalSize = Number.isNaN(_self.totalSize)
                  ? parseInt(resp.headers.get('Content-Range').split('/')[1])
                  : _self.totalSize
                return resp.body.getReader()
              }
            })
            .then(async function(reader) {
              var ok = false
              const chucks = []
              while (!ok) {
                var con = await reader.read()
                ok = con.done
                if (typeof con.value === 'undefined') {
                  break
                }
                chucks.push(con.value)
                _self.downloadedSize += con.value.byteLength
                typeof _self.onprogress === 'function' ? _self.onprogress(_self) : 0
              }
              if (ok) {
                _self.db.attachmentShardingBlob
                  .add({
                    id: _self.name + i,
                    blob: new Blob(chucks),
                    index: i,
                    key: _self.name,
                  })
                  .then(() => {
                    console.log('count---' + i)
                    _self.db.attachmentSharding
                      .put({
                        id: _self.name,
                        count: i,
                        filesize: _self.fileSize,
                      })
                      .then(() => {
                        if (b === _self.fileSize - 1) {
                          _self.running = false
                          _self.loaded = true
                          typeof _self.onload === 'function' ? _self.onload(_self) : 0
                        } else {
                          typeof _self.onprogress === 'function' ? _self.onprogress(_self) : 0
                        }
                      })
                  })
                if (c) {
                  c.download()
                }
                if (cc) {
                  cc.continue()
                }
              }
              _self.index = i
              _self.running = false
              _self.loaded = true
            })
            .catch((e) => {
              if (_self.running === true) {
                typeof _self.onerror === 'function' ? _self.onerror(_self, e) : 0
                throw e
              }
              _self.running = false
            })
        } catch (e) {
          if (_self.running === true) {
            typeof _self.onerror === 'function' ? _self.onerror(_self, e) : 0
            throw e
          }
          _self.running = false
        }
      }
    }
    class Controller {
      constructor(t, i, url, fileSize, chunkSize, abortController) {
        this.i = i
        this.t = t
        this.url = url
        this.fileSize = fileSize
        this.chunkSize = chunkSize
        this.abortController = abortController
      }

      setIndex(i) {
        this.i = i
      }

      download(cc) {
        if (this.t < this.fileSize) {
          const a = this.i * this.chunkSize
          let b = (this.i + 1) * this.chunkSize - 1
          this.t = b
          if (b >= this.fileSize) {
            b = this.fileSize - 1
          }
          const r = a + '-' + b
          const rs = 'bytes=' + r
          module(this.url, r, this.i, b, this.abortController, cc ? null : this, cc)
          this.i++
        }
      }
    }
    class ContinueController {
      constructor(j, url, c) {
        this.j = j
        this.url = url
        this.c = c
      }

      continue() {
        modulejx(this.url, this.j, this.c, this)
        this.j++
      }
    }
    let chunkSize = 1024 * 1024 * 32 // 32M
    if (this.fileSize > 1024 * 1024 * 1024) {
      chunkSize = 1024 * 1024 * 128 // 128M
    }
    let jxflag = false
    _self.db.attachmentSharding.get(_self.name).then((d) => {
      if (d && d.count > 0) {
        jxflag = true
      }
      const count = Math.ceil(this.fileSize / chunkSize)
      _self.dbcount = count
      const c = new Controller(0, 0, this.url, this.fileSize, chunkSize, this.abortController)
      if (jxflag) {
        const cc = new ContinueController(0, this.url, c)
        cc.continue()
      } else {
        c.download()
      }
    })
  }
  RangeDownloader.prototype.pause = function() {
    this.running = false
    this.abortController != null ? this.abortController.abort() : 0
    this.chucks = this.supportPartial ? this.chucks : []
    this.downloadedSize = 0
  }
  RangeDownloader.prototype.cancel = function() {
    this.running = false
    this.abortController != null ? this.abortController.abort() : 0
    this.chucks = []
    this.downloadedSize = 0
    this.totalSize = 0
    this.supportPartial = false
    if (this.oncancle) {
      this.oncancle(self)
    }
  }
  RangeDownloader.prototype.getResultAsBlob = function(release) {
    return new Blob(this.chucks)
  }
  RangeDownloader.prototype.running = false
  RangeDownloader.prototype.url = ''
  RangeDownloader.prototype.fileSize = 0
  RangeDownloader.prototype.name = ''
  RangeDownloader.prototype.onerror = null
  RangeDownloader.prototype.onprogress = null
  RangeDownloader.prototype.onload = null
  RangeDownloader.prototype.supportPartial = false
  RangeDownloader.prototype.chucks = null
  RangeDownloader.prototype.totalSize = 0
  RangeDownloader.prototype.downloadedSize = 0
  RangeDownloader.prototype.index = 0
  RangeDownloader.prototype.indexb = 0
  RangeDownloader.prototype.abortController = null
  RangeDownloader.prototype.loaded = false
  RangeDownloader.prototype.db = null
  RangeDownloader.prototype.dbcount = 0
  return RangeDownloader
})()

export default RangeDownloader
