const got = require('got')
const {_md5, _ecbCrypt, _ecbDecrypt} = require('./utils/crypto.js')

const { USER_AGENT_HEADER, pipeline } = require('./utils/index.js')

function generateStreamPath(sngID, md5, mediaVersion, format){
  let urlPart = md5+"¤"+format+"¤"+sngID+"¤"+mediaVersion
  let md5val = _md5(urlPart)
  let step2 = md5val+"¤"+urlPart+"¤"
  step2 += '.'.repeat(16 - (step2.length % 16))
  urlPart = _ecbCrypt('jo6aey6haid2Teih', step2)
  return urlPart
}

function reverseStreamPath(urlPart){
  let step2 = _ecbDecrypt('jo6aey6haid2Teih', urlPart)
  let [, md5, format, sngID, mediaVersion] = step2.split("¤")
  return [sngID, md5, mediaVersion, format]
}

function generateStreamURL(sngID, md5, mediaVersion, format){
  let urlPart = generateStreamPath(sngID, md5, mediaVersion, format)
  return "https://e-cdns-proxy-" + md5[0] + ".dzcdn.net/api/1/" + urlPart
}

function reverseStreamURL(url){
  let urlPart = url.slice(url.find("/1/")+3)
  return reverseStreamPath(urlPart)
}

async function streamTrack(outputStream, track, start=0, downloadObject, listener){
  if (downloadObject.isCanceled) throw new DownloadCanceled
  let headers = {'User-Agent': USER_AGENT_HEADER}
  let chunkLength = start
  let complete = 0

  let itemData = {
    id: track.id,
    title: track.title,
    artist: track.mainArtist.name
  }
  let error = ''

  let request = got.stream(track.downloadURL, {
    headers: headers,
    retry: 3
  }).on('response', (response)=>{
    complete = parseInt(response.headers["content-length"])
    if (complete == 0) {
      error = "DownloadEmpty"
      request.destroy()
    }
    if (start != 0){
      let responseRange = response.headers["content-range"]
      if (listener) listener.send('downloadInfo', {
        uuid: downloadObject.uuid,
        data: itemData,
        state: "downloading",
        alreadyStarted: true,
        value: responseRange
      })
    }else {
      if (listener) listener.send('downloadInfo', {
        uuid: downloadObject.uuid,
        data: itemData,
        state: "downloading",
        alreadyStarted: false,
        value: complete
      })
    }
  }).on('data', function(chunk){
    if (downloadObject.isCanceled) {
      error = "DownloadCanceled"
      request.destroy()
    }
    chunkLength += chunk.length

    if (downloadObject){
      let chunkProgres
      if (downloadObject.__type__ === "Single"){
        chunkProgres = (chunkLength / (complete + start)) * 100
        downloadObject.progressNext = chunkProgres
      }else{
        chunkProgres = (chunk.length / (complete + start)) / downloadObject.size * 100
        downloadObject.progressNext += chunkProgres
      }
      downloadObject.updateProgress(listener)
    }
  })

  try {
    await pipeline(request, outputStream)
  } catch (e){
    if (e instanceof got.ReadError || e instanceof got.TimeoutError){
      await streamTrack(outputStream, track, chunkLength, downloadObject, listener)
    } else if (request.destroyed) {
      switch (error) {
        case 'DownloadEmpty': throw new DownloadEmpty
        case 'DownloadCanceled': throw new DownloadCanceled
        default: throw e
      }
    } else { throw e }
  }
}

class DownloadEmpty extends Error {
  constructor() {
    super()
    this.name = "DownloadEmpty"
  }
}

class DownloadCanceled extends Error {
  constructor() {
    super()
    this.name = "DownloadCanceled"
  }
}

/*
function generateCryptedStreamURL(sngID, md5, mediaVersion, format){
  let urlPart = generateStreamPath(sngID, md5, mediaVersion, format)
  return "https://e-cdns-proxy-" + md5[0] + ".dzcdn.net/mobile/1/" + urlPart
}
*/

module.exports = {
  generateStreamPath,
  generateStreamURL,
  reverseStreamPath,
  reverseStreamURL,
  streamTrack,
  DownloadEmpty,
  DownloadCanceled
}