import Foundation
import UIKit
import Display
import AsyncDisplayKit

public class CompositeTextNode: ASDisplayNode {
    public enum Component: Equatable {
        case text(NSAttributedString)
        case icon(UIImage)
    }
    
    public var components: [Component] = []
    
    private var textNodes: [Int: ImmediateTextNode] = [:]
    private var iconViews: [Int: UIImageView] = [:]
    
    public var imageTintColor: UIColor? {
        didSet {
            for (_, textNode) in self.textNodes {
                textNode.layer.layerTintColor = self.imageTintColor?.cgColor
            }
            for (_, iconView) in self.iconViews {
                iconView.tintColor = self.imageTintColor
            }
        }
    }
    
    public func update(constrainedSize: CGSize) -> CGSize {
        var validTextIds: [Int] = []
        var validIconIds: [Int] = []
        
        var size = CGSize()
        
        var nextTextId = 0
        var nextIconId = 0
        for component in self.components {
            switch component {
            case let .text(text):
                let id = nextTextId
                nextTextId += 1
                validTextIds.append(id)
                
                let textNode: ImmediateTextNode
                if let current = self.textNodes[id] {
                    textNode = current
                } else {
                    textNode = ImmediateTextNode()
                    textNode.maximumNumberOfLines = 1
                    textNode.insets = UIEdgeInsets(top: 3.0, left: 0.0, bottom: 3.0, right: 0.0)
                    textNode.layer.layerTintColor = self.imageTintColor?.cgColor
                    self.textNodes[id] = textNode
                    self.addSubnode(textNode)
                }
                textNode.attributedText = text
                
                let textSize = textNode.updateLayout(CGSize(width: max(1.0, constrainedSize.width - size.width), height: constrainedSize.height))
                
                textNode.frame = CGRect(origin: CGPoint(x: size.width - textNode.insets.left, y: -textNode.insets.top), size: textSize)
                size.width += textSize.width - textNode.insets.left - textNode.insets.right
                size.height = max(size.height, textSize.height - textNode.insets.top - textNode.insets.bottom)
            case let .icon(icon):
                let id = nextIconId
                nextIconId += 1
                validIconIds.append(id)
                
                let iconView: UIImageView
                if let current = self.iconViews[id] {
                    iconView = current
                } else {
                    iconView = UIImageView()
                    self.iconViews[id] = iconView
                    self.view.addSubview(iconView)
                }
                iconView.image = icon
                iconView.tintColor = self.imageTintColor
                
                let iconSize = icon.size
                if size.width != 0.0 {
                    size.width += 3.0
                }
                iconView.frame = CGRect(origin: CGPoint(x: size.width, y: 3.0 + UIScreenPixel), size: iconSize)
                size.width += iconSize.width
                size.width += 3.0
                size.height = max(size.height, iconSize.height)
            }
            
            if size.width >= constrainedSize.width {
                size.width = constrainedSize.width
                break
            }
        }
        
        var removeTextIds: [Int] = []
        for (id, textNode) in self.textNodes {
            if !validTextIds.contains(id) {
                textNode.removeFromSupernode()
                removeTextIds.append(id)
            }
        }
        for id in removeTextIds {
            self.textNodes.removeValue(forKey: id)
        }
        
        var removeIconIds: [Int] = []
        for (id, iconView) in self.iconViews {
            if !validIconIds.contains(id) {
                iconView.removeFromSuperview()
                removeIconIds.append(id)
            }
        }
        for id in removeIconIds {
            self.iconViews.removeValue(forKey: id)
        }
        
        return size
    }
}