import Foundation
import UIKit

func initializeCompositionLayers(
    layers: [LayerModel],
    assetLibrary: AssetLibrary?,
    frameRate: CGFloat
) -> [MyCompositionLayer] {
    var compositionLayers = [MyCompositionLayer]()
    var layerMap = [Int : MyCompositionLayer]()

    /// Organize the assets into a dictionary of [ID : ImageAsset]
    var childLayers = [LayerModel]()

    for layer in layers {
        if layer.hidden == true {
            let genericLayer = MyNullCompositionLayer(layer: layer)
            compositionLayers.append(genericLayer)
            layerMap[layer.index] = genericLayer
        } else if let shapeLayer = layer as? ShapeLayerModel {
            let shapeContainer = MyShapeCompositionLayer(shapeLayer: shapeLayer)
            compositionLayers.append(shapeContainer)
            layerMap[layer.index] = shapeContainer
        } else if let solidLayer = layer as? SolidLayerModel {
            let solidContainer = MySolidCompositionLayer(solid: solidLayer)
            compositionLayers.append(solidContainer)
            layerMap[layer.index] = solidContainer
        } else if let precompLayer = layer as? PreCompLayerModel,
                  let assetLibrary = assetLibrary,
                  let precompAsset = assetLibrary.precompAssets[precompLayer.referenceID] {
            let precompContainer = MyPreCompositionLayer(precomp: precompLayer,
                                                       asset: precompAsset,
                                                       assetLibrary: assetLibrary,
                                                       frameRate: frameRate)
            compositionLayers.append(precompContainer)
            layerMap[layer.index] = precompContainer
        } else if let imageLayer = layer as? ImageLayerModel,
                  let assetLibrary = assetLibrary,
                  let imageAsset = assetLibrary.imageAssets[imageLayer.referenceID] {
            let imageContainer = MyImageCompositionLayer(imageLayer: imageLayer, size: CGSize(width: imageAsset.width, height: imageAsset.height))
            compositionLayers.append(imageContainer)
            layerMap[layer.index] = imageContainer
        } else if let _ = layer as? TextLayerModel {
            let genericLayer = MyNullCompositionLayer(layer: layer)
            compositionLayers.append(genericLayer)
            layerMap[layer.index] = genericLayer
            /*let textContainer = TextCompositionLayer(textLayer: textLayer, textProvider: textProvider, fontProvider: fontProvider)
            compositionLayers.append(textContainer)
            layerMap[layer.index] = textContainer*/
        } else {
            let genericLayer = MyNullCompositionLayer(layer: layer)
            compositionLayers.append(genericLayer)
            layerMap[layer.index] = genericLayer
        }
        if layer.parent != nil {
            childLayers.append(layer)
        }
    }

    /// Now link children with their parents
    for layerModel in childLayers {
        if let parentID = layerModel.parent {
            let childLayer = layerMap[layerModel.index]
            let parentLayer = layerMap[parentID]
            childLayer?.transformNode.parentNode = parentLayer?.transformNode
        }
    }

    return compositionLayers
}

final class MyAnimationContainer {
    let bounds: CGRect

    var currentFrame: CGFloat = 0.0

    /// Forces the view to update its drawing.
    func forceDisplayUpdate() {
        animationLayers.forEach( { $0.displayWithFrame(frame: currentFrame, forceUpdates: true) })
    }

    var animationLayers: [MyCompositionLayer]

    init(animation: Animation) {
        self.animationLayers = []

        self.bounds = CGRect(origin: CGPoint(), size: CGSize(width: animation.width, height: animation.height))
        let layers = initializeCompositionLayers(layers: animation.layers, assetLibrary: animation.assetLibrary, frameRate: CGFloat(animation.framerate))

        var imageLayers = [MyImageCompositionLayer]()

        var mattedLayer: MyCompositionLayer? = nil

        for layer in layers.reversed() {
            layer.bounds = bounds
            animationLayers.append(layer)
            if let imageLayer = layer as? MyImageCompositionLayer {
                imageLayers.append(imageLayer)
            }
            if let matte = mattedLayer {
                /// The previous layer requires this layer to be its matte
                matte.matteLayer = layer
                mattedLayer = nil
                continue
            }
            if let matte = layer.matteType,
               (matte == .add || matte == .invert) {
                /// We have a layer that requires a matte.
                mattedLayer = layer
            }

            //NOTE
            //addSublayer(layer)
        }
    }

    func setFrame(frame: CGFloat) {
        self.currentFrame = frame
        for animationLayer in self.animationLayers {
            animationLayer.displayWithFrame(frame: frame, forceUpdates: false)
        }
    }

    func captureGeometry() -> CapturedGeometryNode {
        var subnodes: [CapturedGeometryNode] = []
        for animationLayer in self.animationLayers {
            let capturedSubnode = animationLayer.captureGeometry()
            subnodes.append(capturedSubnode)
        }
        return CapturedGeometryNode(
            transform: CATransform3DIdentity,
            alpha: 1.0,
            isHidden: false,
            displayItem: nil,
            subnodes: subnodes
        )
    }
}