//
//  AssetLibrary.swift
//  lottie-swift
//
//  Created by Brandon Withrow on 1/9/19.
//

import Foundation

final class AssetLibrary: Codable, AnyInitializable {

  // MARK: Lifecycle

  required init(from decoder: Decoder) throws {
    var container = try decoder.unkeyedContainer()
    var containerForKeys = container

    var decodedAssets = [String : Asset]()

    var imageAssets = [String : ImageAsset]()
    var precompAssets = [String : PrecompAsset]()

    while !container.isAtEnd {
      let keyContainer = try containerForKeys.nestedContainer(keyedBy: PrecompAsset.CodingKeys.self)
      if keyContainer.contains(.layers) {
        let precompAsset = try container.decode(PrecompAsset.self)
        decodedAssets[precompAsset.id] = precompAsset
        precompAssets[precompAsset.id] = precompAsset
      } else {
        let imageAsset = try container.decode(ImageAsset.self)
        decodedAssets[imageAsset.id] = imageAsset
        imageAssets[imageAsset.id] = imageAsset
      }
    }
    assets = decodedAssets
    self.precompAssets = precompAssets
    self.imageAssets = imageAssets
  }

  init(value: Any) throws {
    guard let dictionaries = value as? [[String: Any]] else {
      throw InitializableError.invalidInput
    }
    var decodedAssets = [String : Asset]()
    var imageAssets = [String : ImageAsset]()
    var precompAssets = [String : PrecompAsset]()
    try dictionaries.forEach { dictionary in
      if dictionary[PrecompAsset.CodingKeys.layers.rawValue] != nil {
        let asset = try PrecompAsset(dictionary: dictionary)
        decodedAssets[asset.id] = asset
        precompAssets[asset.id] = asset
      } else {
        let asset = try ImageAsset(dictionary: dictionary)
        decodedAssets[asset.id] = asset
        imageAssets[asset.id] = asset
      }
    }
    assets = decodedAssets
    self.precompAssets = precompAssets
    self.imageAssets = imageAssets
  }

  // MARK: Internal

  /// The Assets
  let assets: [String: Asset]

  let imageAssets: [String: ImageAsset]
  let precompAssets: [String: PrecompAsset]

  func encode(to encoder: Encoder) throws {
    var container = encoder.unkeyedContainer()
    try container.encode(contentsOf: Array(assets.values))
  }
}
