//  Copyright © 2019 650 Industries. All rights reserved.

import Foundation
import EXManifests

public final class EmbeddedUpdate: Update {
  /**
   * Method for initializing updates from the bare-bones-styles manifests embedded in application
   * binaries. These manifest objects are generated by the script at
   * expo-updates/scripts/createManifest.js and describe the update embedded by react-native in the
   * application binary. They contain the minimum amount of information needed to reliably identify
   * the update and insert it into SQLite.
   */
  public static func update(
    withEmbeddedManifest: EmbeddedManifest,
    config: UpdatesConfig,
    database: UpdatesDatabase?
  ) -> EmbeddedUpdate {
    let manifest = withEmbeddedManifest

    let updateId = manifest.rawId()
    let commitTime = manifest.commitTimeNumber()
    let assets = manifest.assets()

    let uuid = UUID(uuidString: updateId).require("update ID should be a valid UUID")

    var processedAssets: [UpdateAsset] = []

    // use unsanitized id value from manifest
    let bundleKey = String(format: "bundle-%@", updateId)
    let jsBundleAsset = UpdateAsset(key: bundleKey, type: EmbeddedAppLoader.EXUpdatesBareEmbeddedBundleFileType)
    jsBundleAsset.isLaunchAsset = true
    jsBundleAsset.mainBundleFilename = EmbeddedAppLoader.EXUpdatesBareEmbeddedBundleFilename
    processedAssets.append(jsBundleAsset)

    assets?.forEach { assetDict in
      let packagerHash: String = assetDict.requiredValue(forKey: "packagerHash")
      let type: String = assetDict.requiredValue(forKey: "type")
      let mainBundleDir: String? = assetDict.optionalValue(forKey: "nsBundleDir")
      let mainBundleFilename: String = assetDict.requiredValue(forKey: "nsBundleFilename")

      let key = packagerHash
      let asset = UpdateAsset(key: key, type: type)
      asset.mainBundleDir = mainBundleDir
      asset.mainBundleFilename = mainBundleFilename
      processedAssets.append(asset)
    }

    return EmbeddedUpdate.init(
      manifest: manifest,
      config: config,
      database: database,
      updateId: uuid,
      scopeKey: config.scopeKey,
      commitTime: Date(timeIntervalSince1970: Double(commitTime) / 1000),
      runtimeVersion: config.runtimeVersion,
      keep: true,
      status: UpdateStatus.StatusEmbedded,
      isDevelopmentMode: false,
      assetsFromManifest: processedAssets,
      url: config.originalEmbeddedUpdateUrl,
      requestHeaders: config.originalEmbeddedRequestHeaders
    )
  }
}
