//
// © 2017-2020 Qualcomm Technologies, Inc. and/or its subsidiaries. All rights reserved.
//

import UIKit
import AVFoundation
import CocoaLumberjack

class LocalMusicLibraryExporter {
	let cache = LocalMusicLibraryExporterCache()

	private enum FileFormats {
		case mp3
		case wav
		case mp4
		case m4a
		
		static func from(string ext: String) -> FileFormats? {
			if ext == "mp3" {
				return .mp3
			}
			if ext == "wav" {
				return .wav
			}
			if ext == "mp4" {
				return .mp4
			}
			if ext == "m4a" {
				return .m4a
			}
			return nil
		}
		
		var exporterPreset: String {
			switch self {
			case .mp3:
				return AVAssetExportPresetPassthrough
			case .wav:
				return AVAssetExportPresetPassthrough
			case .mp4:
				return AVAssetExportPresetPassthrough
			case .m4a:
				return AVAssetExportPresetAppleM4A
			}
		}
		
		var outputFileType: AVFileType {
			switch self {
			case .mp3:
				return .mov
			case .wav:
				return .wav
			case .mp4:
				//return .mp4
				return .mp4
			case .m4a:
				return .m4a
				//return .m4a
			}
		}
		
		// Returns a MimeType for each audio file format
		var mimeType: String {
			switch self {
			case .mp3:
				return "audio/mpeg"
			case .wav:
				return "audio/vnd.wav"
			case .mp4:
				return "audio/mov"
			case .m4a:
				return "audio/mov"
			}
		}
	}
}

// MARK: - Public Methods
extension LocalMusicLibraryExporter {
	func export(id: UInt64,
				assetURL: URL,
				completion: @escaping (_ data: Data?, _ mimeType: String?) -> ()) {
		
		// Is it supported file format
		let ext = assetURL.pathExtension.lowercased()
		DDLogVerbose("Asset URL: \(assetURL)")
		guard let format = FileFormats.from(string: ext) else {
			DDLogVerbose("Unsupported format : \(ext)")
			completion(nil, nil)
			return
		}
		
		if let cached = cache.dataForAssetURL(assetURL) {
			completion(cached, format.mimeType)
			return
		}
		
		let asset = AVAsset(url: assetURL)

		guard let exportSession = AVAssetExportSession(asset: asset, presetName: format.exporterPreset) else {
			DDLogVerbose("CANNOT EXPORT")
			completion(nil, nil)
			return
		}
		
		exportSession.outputFileType = format.outputFileType
		exportSession.outputURL = cache.urlForAssetURL(assetURL)
		exportSession.shouldOptimizeForNetworkUse = true
		
		exportSession.exportAsynchronously(completionHandler: { [weak self] in
			guard let self = self else {
				completion(nil, nil)
				return
			}
			if exportSession.status == .completed {
				if let cached = self.cache.dataForAssetURL(assetURL) {
					completion(cached, format.mimeType)
					self.cache.didAddToCache(assetURL)
				} else {
					completion(nil, nil)
				}
			} else {
				completion(nil, nil)
			}
		})
	}

}
