const Path = require('path')

const SocketAuthority = require('../SocketAuthority')
const Logger = require('../Logger')

const fs = require('../libs/fsExtra')

const { secondsToTimestamp } = require('../utils/index')
const toneHelpers = require('../utils/toneHelpers')
const filePerms = require('../utils/filePerms')

class AudioMetadataMangaer {
  constructor(db, taskManager) {
    this.db = db
    this.taskManager = taskManager
  }

  getToneMetadataObjectForApi(libraryItem) {
    return toneHelpers.getToneMetadataObject(libraryItem)
  }

  async updateMetadataForItem(user, libraryItem, options = {}) {
    const forceEmbedChapters = !!options.forceEmbedChapters
    const backupFiles = !!options.backup

    const audioFiles = libraryItem.media.includedAudioFiles

    const itemAudioMetadataPayload = {
      userId: user.id,
      libraryItemId: libraryItem.id,
      startedAt: Date.now(),
      audioFiles: audioFiles.map(af => ({ index: af.index, ino: af.ino, filename: af.metadata.filename }))
    }

    SocketAuthority.emitter('audio_metadata_started', itemAudioMetadataPayload)

    // Ensure folder for backup files
    const itemCacheDir = Path.join(global.MetadataPath, `cache/items/${libraryItem.id}`)
    let cacheDirCreated = false
    if (!await fs.pathExists(itemCacheDir)) {
      await fs.mkdir(itemCacheDir)
      await filePerms.setDefault(itemCacheDir, true)
      cacheDirCreated = true
    }

    // Write chapters file
    const toneJsonPath = Path.join(itemCacheDir, 'metadata.json')

    try {
      const chapters = (audioFiles.length == 1 || forceEmbedChapters) ? libraryItem.media.chapters : null
      await toneHelpers.writeToneMetadataJsonFile(libraryItem, chapters, toneJsonPath, audioFiles.length)
    } catch (error) {
      Logger.error(`[AudioMetadataManager] Write metadata.json failed`, error)

      itemAudioMetadataPayload.failed = true
      itemAudioMetadataPayload.error = 'Failed to write metadata.json'
      SocketAuthority.emitter('audio_metadata_finished', itemAudioMetadataPayload)
      return
    }

    const results = []
    for (const af of audioFiles) {
      const result = await this.updateAudioFileMetadataWithTone(libraryItem, af, toneJsonPath, itemCacheDir, backupFiles)
      results.push(result)
    }

    // Remove temp cache file/folder if not backing up
    if (!backupFiles) {
      // If cache dir was created from this then remove it
      if (cacheDirCreated) {
        await fs.remove(itemCacheDir)
      } else {
        await fs.remove(toneJsonPath)
      }
    }

    const elapsed = Date.now() - itemAudioMetadataPayload.startedAt
    Logger.debug(`[AudioMetadataManager] Elapsed ${secondsToTimestamp(elapsed / 1000, true)}`)
    itemAudioMetadataPayload.results = results
    itemAudioMetadataPayload.elapsed = elapsed
    itemAudioMetadataPayload.finishedAt = Date.now()
    SocketAuthority.emitter('audio_metadata_finished', itemAudioMetadataPayload)
  }

  async updateAudioFileMetadataWithTone(libraryItem, audioFile, toneJsonPath, itemCacheDir, backupFiles) {
    const resultPayload = {
      libraryItemId: libraryItem.id,
      index: audioFile.index,
      ino: audioFile.ino,
      filename: audioFile.metadata.filename
    }
    SocketAuthority.emitter('audiofile_metadata_started', resultPayload)

    // Backup audio file
    if (backupFiles) {
      try {
        const backupFilePath = Path.join(itemCacheDir, audioFile.metadata.filename)
        await fs.copy(audioFile.metadata.path, backupFilePath)
        Logger.debug(`[AudioMetadataManager] Backed up audio file at "${backupFilePath}"`)
      } catch (err) {
        Logger.error(`[AudioMetadataManager] Failed to backup audio file "${audioFile.metadata.path}"`, err)
      }
    }

    const _toneMetadataObject = {
      'ToneJsonFile': toneJsonPath,
      'TrackNumber': audioFile.index,
    }

    if (libraryItem.media.coverPath) {
      _toneMetadataObject['CoverFile'] = libraryItem.media.coverPath
    }

    resultPayload.success = await toneHelpers.tagAudioFile(audioFile.metadata.path, _toneMetadataObject)
    if (resultPayload.success) {
      Logger.info(`[AudioMetadataManager] Successfully tagged audio file "${audioFile.metadata.path}"`)
    }

    SocketAuthority.emitter('audiofile_metadata_finished', resultPayload)
    return resultPayload
  }
}
module.exports = AudioMetadataMangaer