const uuidv4 = require("uuid").v4

class MediaProgress {
  constructor(progress) {
    this.id = null
    this.userId = null
    this.libraryItemId = null
    this.episodeId = null // For podcasts

    this.mediaItemId = null // For use in new data model
    this.mediaItemType = null // For use in new data model

    this.duration = null
    this.progress = null // 0 to 1
    this.currentTime = null // seconds
    this.isFinished = false
    this.hideFromContinueListening = false

    this.ebookLocation = null // cfi tag for epub, page number for pdf
    this.ebookProgress = null // 0 to 1

    this.lastUpdate = null
    this.startedAt = null
    this.finishedAt = null

    if (progress) {
      this.construct(progress)
    }
  }

  toJSON() {
    return {
      id: this.id,
      userId: this.userId,
      libraryItemId: this.libraryItemId,
      episodeId: this.episodeId,
      mediaItemId: this.mediaItemId,
      mediaItemType: this.mediaItemType,
      duration: this.duration,
      progress: this.progress,
      currentTime: this.currentTime,
      isFinished: this.isFinished,
      hideFromContinueListening: this.hideFromContinueListening,
      ebookLocation: this.ebookLocation,
      ebookProgress: this.ebookProgress,
      lastUpdate: this.lastUpdate,
      startedAt: this.startedAt,
      finishedAt: this.finishedAt
    }
  }

  construct(progress) {
    this.id = progress.id
    this.userId = progress.userId
    this.libraryItemId = progress.libraryItemId
    this.episodeId = progress.episodeId
    this.mediaItemId = progress.mediaItemId
    this.mediaItemType = progress.mediaItemType
    this.duration = progress.duration || 0
    this.progress = progress.progress
    this.currentTime = progress.currentTime || 0
    this.isFinished = !!progress.isFinished
    this.hideFromContinueListening = !!progress.hideFromContinueListening
    this.ebookLocation = progress.ebookLocation || null
    this.ebookProgress = progress.ebookProgress || null
    this.lastUpdate = progress.lastUpdate
    this.startedAt = progress.startedAt
    this.finishedAt = progress.finishedAt || null
  }

  get inProgress() {
    return !this.isFinished && (this.progress > 0 || (this.ebookLocation != null && this.ebookProgress > 0))
  }

  get notStarted() {
    return !this.isFinished && this.progress == 0
  }

  setData(libraryItem, progress, episodeId, userId) {
    this.id = uuidv4()
    this.userId = userId
    this.libraryItemId = libraryItem.id
    this.episodeId = episodeId

    // PodcastEpisodeId or BookId
    this.mediaItemId = episodeId || libraryItem.media.id
    this.mediaItemType = episodeId ? 'podcastEpisode' : 'book'

    this.duration = progress.duration || 0
    this.progress = Math.min(1, (progress.progress || 0))
    this.currentTime = progress.currentTime || 0
    this.isFinished = !!progress.isFinished || this.progress == 1
    this.hideFromContinueListening = !!progress.hideFromContinueListening
    this.ebookLocation = progress.ebookLocation
    this.ebookProgress = Math.min(1, (progress.ebookProgress || 0))
    this.lastUpdate = Date.now()
    this.finishedAt = null
    if (this.isFinished) {
      this.finishedAt = progress.finishedAt || Date.now()
      this.progress = 1
    }
    this.startedAt = progress.startedAt || this.finishedAt || Date.now()
  }

  update(payload) {
    let hasUpdates = false
    for (const key in payload) {
      if (this[key] !== undefined && payload[key] !== this[key]) {
        if (key === 'isFinished') {
          if (!payload[key]) { // Updating to Not Finished - Reset progress and current time
            this.finishedAt = null
            this.progress = 0
            this.currentTime = 0
          } else { // Updating to Finished
            if (!this.finishedAt) this.finishedAt = Date.now()
            this.progress = 1
          }
        }

        this[key] = payload[key]
        hasUpdates = true
      }
    }

    var timeRemaining = this.duration - this.currentTime
    // If time remaining is less than 5 seconds then mark as finished
    if ((this.progress >= 1 || (this.duration && !isNaN(timeRemaining) && timeRemaining < 5))) {
      this.isFinished = true
      this.finishedAt = payload.finishedAt || Date.now()
      this.progress = 1
    } else if (this.progress < 1 && this.isFinished) {
      this.isFinished = false
      this.finishedAt = null
    }

    if (!this.startedAt) {
      this.startedAt = this.finishedAt || Date.now()
    }
    if (hasUpdates) {
      if (payload.hideFromContinueListening === undefined) {
        // Reset this flag when the media progress is updated
        this.hideFromContinueListening = false
      }

      this.lastUpdate = Date.now()
    }
    return hasUpdates
  }

  removeFromContinueListening() {
    if (this.hideFromContinueListening) return false

    this.hideFromContinueListening = true
    return true
  }
}
module.exports = MediaProgress