import Foundation
import UIKit
import Display
import TelegramCore
import SwiftSignalKit
import AsyncDisplayKit
import StickerResources
import AccountContext
import AnimatedStickerNode
import TelegramAnimatedStickerNode
import TelegramPresentationData
import ShimmerEffect

final class StickerPackPreviewInteraction {
    var previewedItem: ImportStickerPack.Sticker?
    var playAnimatedStickers: Bool
    
    init(playAnimatedStickers: Bool) {
        self.playAnimatedStickers = playAnimatedStickers
    }
}

final class StickerPackPreviewGridItem: GridItem {
    let account: Account
    let stickerItem: ImportStickerPack.Sticker
    let interaction: StickerPackPreviewInteraction
    let theme: PresentationTheme
    let isVerified: Bool
    
    let section: GridSection? = nil
    
    init(account: Account, stickerItem: ImportStickerPack.Sticker, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isVerified: Bool) {
        self.account = account
        self.stickerItem = stickerItem
        self.interaction = interaction
        self.theme = theme
        self.isVerified = isVerified
    }
    
    func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
        let node = StickerPackPreviewGridItemNode()
        node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isVerified: self.isVerified)
        return node
    }
    
    func update(node: GridItemNode) {
        guard let node = node as? StickerPackPreviewGridItemNode else {
            assertionFailure()
            return
        }
        node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isVerified: self.isVerified)
    }
}

private let textFont = Font.regular(20.0)

final class StickerPackPreviewGridItemNode: GridItemNode {
    private var currentState: (Account, ImportStickerPack.Sticker?, CGSize)?
    private var isVerified: Bool?
    private let imageNode: ASImageNode
    private var animationNode: AnimatedStickerNode?
    private var placeholderNode: ShimmerEffectNode?
    
    private var theme: PresentationTheme?
    
    override var isVisibleInGrid: Bool {
        didSet {
            self.animationNode?.visibility = self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true
        }
    }
    
    private var currentIsPreviewing = false
    
    private let stickerFetchedDisposable = MetaDisposable()
    
    var interaction: StickerPackPreviewInteraction?
    
    var selected: (() -> Void)?
    
    var stickerPackItem: ImportStickerPack.Sticker? {
        return self.currentState?.1
    }
    
    override init() {
        self.imageNode = ASImageNode()
        
        super.init()
        
        self.addSubnode(self.imageNode)
    }
    
    deinit {
        self.stickerFetchedDisposable.dispose()
    }
    
    override func didLoad() {
        super.didLoad()
        
        self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
    }
    
    func setup(account: Account, stickerItem: ImportStickerPack.Sticker?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isVerified: Bool) {
        self.interaction = interaction
        self.theme = theme
        
        if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 !== stickerItem || self.isVerified != isVerified {
            var dimensions = CGSize(width: 512.0, height: 512.0)
            if let stickerItem = stickerItem {
                switch stickerItem.content {
                    case let .image(data):
                        if let animationNode = self.animationNode {
                            animationNode.visibility = false
                            self.animationNode = nil
                            animationNode.removeFromSupernode()
                        }
                        self.imageNode.isHidden = false
                        if let image = UIImage(data: data) {
                            self.imageNode.image = image
                            dimensions = image.size
                        }
                    case .animation, .video:
                        self.imageNode.isHidden = true
                        
                        if isVerified {
                            let animationNode = DefaultAnimatedStickerNodeImpl()
                            self.animationNode = animationNode
                            
                            if let placeholderNode = self.placeholderNode {
                                self.placeholderNode = nil
                                placeholderNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak placeholderNode] _ in
                                    placeholderNode?.removeFromSupernode()
                                })
                                self.insertSubnode(animationNode, belowSubnode: placeholderNode)
                            } else {
                                self.addSubnode(animationNode)
                            }
                            
                            let fittedDimensions = dimensions.aspectFitted(CGSize(width: 160.0, height: 160.0))
                            if let resource = stickerItem.resource {
                                var isVideo = false
                                if case .video = stickerItem.content {
                                    isVideo = true
                                }
                                animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource._asResource(), isVideo: isVideo), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .direct(cachePathPrefix: nil))
                            }
                            animationNode.visibility = self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true
                        } else {
                            let placeholderNode = ShimmerEffectNode()
                            self.placeholderNode = placeholderNode

                            self.addSubnode(placeholderNode)
                            if let (absoluteRect, containerSize) = self.absoluteLocation {
                                placeholderNode.updateAbsoluteRect(absoluteRect, within: containerSize)
                            }
                        }
                }
            } else {
                dimensions = CGSize()
            }
            self.currentState = (account, stickerItem, dimensions)
            self.setNeedsLayout()
        }
        self.isVerified = isVerified
    }
    
    override func layout() {
        super.layout()
        
        let bounds = self.bounds
        let boundsSide = min(bounds.size.width - 14.0, bounds.size.height - 14.0)
        let boundingSize = CGSize(width: boundsSide, height: boundsSide)
        
        if let (_, _, dimensions) = self.currentState {
            let imageSize = dimensions.aspectFitted(boundingSize)
            self.imageNode.frame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
            if let animationNode = self.animationNode {
                animationNode.frame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
                animationNode.updateLayout(size: imageSize)
            }
            
            if let placeholderNode = self.placeholderNode, let theme = self.theme {
                placeholderNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: [.roundedRect(rect: CGRect(origin: CGPoint(), size: imageSize), cornerRadius: 11.0)], horizontal: true, size: imageSize)
                placeholderNode.frame = self.imageNode.frame
            }
        }
    }
    
    func transitionNode() -> ASDisplayNode? {
        return self
    }
    
    @objc func imageNodeTap(_ recognizer: UITapGestureRecognizer) {
    }
    
    func updatePreviewing(animated: Bool) {
        var isPreviewing = false
        if let (_, maybeItem, _) = self.currentState, let interaction = self.interaction, let item = maybeItem {
            isPreviewing = interaction.previewedItem === item
        }
        if self.currentIsPreviewing != isPreviewing {
            self.currentIsPreviewing = isPreviewing
            
            if isPreviewing {
                self.layer.sublayerTransform = CATransform3DMakeScale(0.8, 0.8, 1.0)
                if animated {
                    self.layer.animateSpring(from: 1.0 as NSNumber, to: 0.8 as NSNumber, keyPath: "sublayerTransform.scale", duration: 0.4)
                }
            } else {
                self.layer.sublayerTransform = CATransform3DIdentity
                if animated {
                    self.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "sublayerTransform.scale", duration: 0.5)
                }
            }
        }
    }
    
    var absoluteLocation: (CGRect, CGSize)?
    override func updateAbsoluteRect(_ absoluteRect: CGRect, within containerSize: CGSize) {
        self.absoluteLocation = (absoluteRect, containerSize)
        if let placeholderNode = self.placeholderNode {
            placeholderNode.updateAbsoluteRect(absoluteRect, within: containerSize)
        }
    }
}