import Foundation
import UIKit
import AsyncDisplayKit
import Display
import Postbox
import TelegramCore
import SwiftSignalKit
import TelegramPresentationData
import AccountContext
import AppBundle
import ChatPresentationInterfaceState
import ChatInputPanelNode
import ReactionSelectionNode
import EntityKeyboard
import TopMessageReactions

private final class ChatMessageSelectionInputPanelNodeViewForOverlayContent: UIView, ChatInputPanelViewForOverlayContent {
    var reactionContextNode: ReactionContextNode?
    var anchorRect: CGRect?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.backgroundTapGesture(_:))))
    }
    
    required init(coder: NSCoder) {
        preconditionFailure()
    }
    
    @objc private func backgroundTapGesture(_ recognizer: UITapGestureRecognizer) {
        if case .ended = recognizer.state {
            self.dismissReactionSelection()
        }
    }
    
    func dismissReactionSelection() {
        if let reactionContextNode = self.reactionContextNode {
            self.reactionContextNode = nil
            reactionContextNode.animateOut(to: self.anchorRect, animatingOutToReaction: false)
            ContainedViewLayoutTransition.animated(duration: 0.25, curve: .easeInOut).updateAlpha(node: reactionContextNode, alpha: 0.0, completion: { [weak reactionContextNode] _ in
                reactionContextNode?.removeFromSupernode()
            })
        }
    }
    
    func maybeDismissContent(point: CGPoint) {
        if self.hitTest(point, with: nil) == self {
            self.dismissReactionSelection()
        }
    }
    
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        if let reactionContextNode = self.reactionContextNode {
            if let result = reactionContextNode.view.hitTest(self.convert(point, to: reactionContextNode.view), with: event) {
                return result
            }
            return self
        }
        return nil
    }
}

public final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
    private let deleteButton: HighlightableButtonNode
    private let reportButton: HighlightableButtonNode
    private let forwardButton: HighlightableButtonNode
    private let shareButton: HighlightableButtonNode
    private let tagButton: HighlightableButtonNode
    private let tagEditButton: HighlightableButtonNode
    private let separatorNode: ASDisplayNode
    
    private let reactionOverlayContainer: ChatMessageSelectionInputPanelNodeViewForOverlayContent
    
    private var validLayout: (width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, metrics: LayoutMetrics, isSecondary: Bool, isMediaInputExpanded: Bool)?
    private var presentationInterfaceState: ChatPresentationInterfaceState?
    private var actions: ChatAvailableMessageActions?
    
    private var theme: PresentationTheme
    private let peerMedia: Bool
    
    private let canDeleteMessagesDisposable = MetaDisposable()
    
    public var selectedMessages = Set<MessageId>() {
        didSet {
            if oldValue != self.selectedMessages {
                self.updateActions()
            }
        }
    }
    
    public init(theme: PresentationTheme, strings: PresentationStrings, peerMedia: Bool = false) {
        self.theme = theme
        self.peerMedia = peerMedia
        
        self.deleteButton = HighlightableButtonNode(pointerStyle: .rectangle(CGSize(width: 56.0, height: 40.0)))
        self.deleteButton.isEnabled = false
        self.deleteButton.isAccessibilityElement = true
        self.deleteButton.accessibilityLabel = strings.VoiceOver_MessageContextDelete
        
        self.reportButton = HighlightableButtonNode(pointerStyle: .rectangle(CGSize(width: 56.0, height: 40.0)))
        self.reportButton.isEnabled = false
        self.reportButton.isAccessibilityElement = true
        self.reportButton.accessibilityLabel = strings.VoiceOver_MessageContextReport
        
        self.forwardButton = HighlightableButtonNode(pointerStyle: .rectangle(CGSize(width: 56.0, height: 40.0)))
        self.forwardButton.isAccessibilityElement = true
        self.forwardButton.accessibilityLabel = strings.VoiceOver_MessageContextForward
        
        self.shareButton = HighlightableButtonNode(pointerStyle: .rectangle(CGSize(width: 56.0, height: 40.0)))
        self.shareButton.isAccessibilityElement = true
        self.shareButton.accessibilityLabel = strings.VoiceOver_MessageContextShare
        
        self.tagButton = HighlightableButtonNode(pointerStyle: .rectangle(CGSize(width: 56.0, height: 40.0)))
        self.tagButton.isAccessibilityElement = true
        self.tagButton.accessibilityLabel = strings.VoiceOver_MessageSelectionButtonTag
        
        self.tagEditButton = HighlightableButtonNode(pointerStyle: .rectangle(CGSize(width: 56.0, height: 40.0)))
        self.tagEditButton.isAccessibilityElement = true
        self.tagEditButton.accessibilityLabel = strings.VoiceOver_MessageSelectionButtonTag
        
        self.deleteButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
        self.deleteButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
        self.reportButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionReport"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
        self.reportButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionReport"), color: theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
        self.forwardButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
        self.forwardButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
        self.shareButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
        self.shareButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
        self.tagButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/TagIcon"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
        self.tagEditButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/TagEditIcon"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
        
        self.separatorNode = ASDisplayNode()
        self.separatorNode.backgroundColor = theme.chat.inputPanel.panelSeparatorColor
        
        self.reactionOverlayContainer = ChatMessageSelectionInputPanelNodeViewForOverlayContent()
        
        super.init()
        
        self.addSubnode(self.deleteButton)
        self.addSubnode(self.reportButton)
        self.addSubnode(self.forwardButton)
        self.addSubnode(self.shareButton)
        self.addSubnode(self.tagButton)
        self.addSubnode(self.tagEditButton)
        self.addSubnode(self.separatorNode)
        
        self.viewForOverlayContent = self.reactionOverlayContainer
        
        self.forwardButton.isImplicitlyDisabled = true
        self.shareButton.isImplicitlyDisabled = true
        
        self.deleteButton.addTarget(self, action: #selector(self.deleteButtonPressed), forControlEvents: .touchUpInside)
        self.reportButton.addTarget(self, action: #selector(self.reportButtonPressed), forControlEvents: .touchUpInside)
        self.forwardButton.addTarget(self, action: #selector(self.forwardButtonPressed), forControlEvents: .touchUpInside)
        self.shareButton.addTarget(self, action: #selector(self.shareButtonPressed), forControlEvents: .touchUpInside)
        self.tagButton.addTarget(self, action: #selector(self.tagButtonPressed), forControlEvents: .touchUpInside)
        self.tagEditButton.addTarget(self, action: #selector(self.tagButtonPressed), forControlEvents: .touchUpInside)
    }
    
    deinit {
        self.canDeleteMessagesDisposable.dispose()
    }
    
    private func updateActions() {
        self.forwardButton.isEnabled = self.selectedMessages.count != 0
        
        if self.selectedMessages.isEmpty {
            self.actions = nil
            if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary, isMediaInputExpanded) = self.validLayout, let interfaceState = self.presentationInterfaceState {
                let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: interfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded)
            }
            self.canDeleteMessagesDisposable.set(nil)
        } else if let context = self.context {
            self.canDeleteMessagesDisposable.set((context.sharedContext.chatAvailableMessageActions(engine: context.engine, accountPeerId: context.account.peerId, messageIds: self.selectedMessages, keepUpdated: true)
            |> deliverOnMainQueue).startStrict(next: { [weak self] actions in
                if let strongSelf = self {
                    strongSelf.actions = actions
                    if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary, isMediaInputExpanded) = strongSelf.validLayout, let interfaceState = strongSelf.presentationInterfaceState {
                        let _ = strongSelf.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: .immediate, interfaceState: interfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded)
                    }
                }
            }))
        }
    }
    
    public func updateTheme(theme: PresentationTheme) {
        if self.theme !== theme {
            self.theme = theme
            
            self.deleteButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
            self.deleteButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
            self.reportButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionReport"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
            self.reportButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionReport"), color: theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
            self.forwardButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
            self.forwardButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
            self.shareButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
            self.shareButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
            self.tagButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/WebpageIcon"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
            self.tagEditButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/LinkSettingsIcon"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
            
            self.separatorNode.backgroundColor = theme.chat.inputPanel.panelSeparatorColor
        }
    }
    
    @objc private func deleteButtonPressed() {
        self.interfaceInteraction?.deleteSelectedMessages()
    }
    
    @objc private func reportButtonPressed() {
        self.interfaceInteraction?.reportSelectedMessages()
    }
    
    @objc private func forwardButtonPressed() {
        if let _ = self.presentationInterfaceState?.renderedPeer?.peer as? TelegramSecretChat {
            return
        }
        if let actions = self.actions, actions.isCopyProtected {
            self.interfaceInteraction?.displayCopyProtectionTip(self.forwardButton, false)
        } else if !self.forwardButton.isImplicitlyDisabled {
            self.interfaceInteraction?.forwardSelectedMessages()
        }
    }
    
    @objc private func shareButtonPressed() {
        if let _ = self.presentationInterfaceState?.renderedPeer?.peer as? TelegramSecretChat {
            return
        }
        if let actions = self.actions, actions.isCopyProtected {
            self.interfaceInteraction?.displayCopyProtectionTip(self.shareButton, true)
        } else if !self.shareButton.isImplicitlyDisabled {
            self.interfaceInteraction?.shareSelectedMessages()
        }
    }
    
    @objc private func tagButtonPressed() {
        guard let context = self.context else {
            return
        }
        
        if self.reactionOverlayContainer.reactionContextNode != nil {
            return
        }
        
        let reactionItems: Signal<[ReactionItem], NoError> = tagMessageReactions(context: context, subPeerId: self.presentationInterfaceState?.chatLocation.threadId.flatMap(EnginePeer.Id.init))
        
        let _ = (reactionItems
        |> take(1)
        |> deliverOnMainQueue).start(next: { [weak self] reactionItems in
            guard let self, let actions = self.actions, let context = self.context else {
                return
            }
            
            let presentationData = context.sharedContext.currentPresentationData.with { $0 }
            
            let reactionContextNode = ReactionContextNode(
                context: context,
                animationCache: context.animationCache,
                presentationData: presentationData,
                items: reactionItems.map { ReactionContextItem.reaction(item: $0, icon: .none) },
                selectedItems: actions.editTags,
                title: actions.editTags.isEmpty ? presentationData.strings.Chat_ReactionSelectionTitleAddTag : presentationData.strings.Chat_ReactionSelectionTitleEditTag,
                reactionsLocked: false,
                alwaysAllowPremiumReactions: false,
                allPresetReactionsAreAvailable: true,
                getEmojiContent: { animationCache, animationRenderer in
                    let mappedReactionItems: [EmojiComponentReactionItem] = reactionItems.map { reaction -> EmojiComponentReactionItem in
                        return EmojiComponentReactionItem(reaction: reaction.reaction.rawValue, file: reaction.stillAnimation)
                    }
                    
                    return EmojiPagerContentComponent.emojiInputData(
                        context: context,
                        animationCache: animationCache,
                        animationRenderer: animationRenderer,
                        isStandalone: false,
                        subject: .messageTag,
                        hasTrending: false,
                        topReactionItems: mappedReactionItems,
                        areUnicodeEmojiEnabled: false,
                        areCustomEmojiEnabled: true,
                        chatPeerId: context.account.peerId,
                        selectedItems: Set(),
                        premiumIfSavedMessages: false
                    )
                },
                isExpandedUpdated: { [weak self] transition in
                    guard let self else {
                        return
                    }
                    self.update(transition: transition)
                },
                requestLayout: { [weak self] transition in
                    guard let self else {
                        return
                    }
                    self.update(transition: transition)
                },
                requestUpdateOverlayWantsToBeBelowKeyboard: { [weak self] transition in
                    guard let self else {
                        return
                    }
                    self.update(transition: transition)
                }
            )
            reactionContextNode.reactionSelected = { [weak self] updateReaction, _ in
                guard let self, let context = self.context, let presentationInterfaceState = self.presentationInterfaceState, let actions = self.actions else {
                    return
                }
                
                self.interfaceInteraction?.cancelMessageSelection(.animated(duration: 0.4, curve: .spring))
                
                if actions.editTags.contains(updateReaction.reaction) {
                    var reactions = actions.editTags
                    reactions.remove(updateReaction.reaction)
                    let mappedUpdatedReactions = reactions.map { reaction -> UpdateMessageReaction in
                        switch reaction {
                        case let .builtin(value):
                            return .builtin(value)
                        case let .custom(fileId):
                            return .custom(fileId: fileId, file: nil)
                        case .stars:
                            return .stars
                        }
                    }
                    if let selectionState = presentationInterfaceState.interfaceState.selectionState {
                        context.engine.messages.setMessageReactions(ids: Array(selectionState.selectedIds), reactions: mappedUpdatedReactions)
                    } else {
                        context.engine.messages.setMessageReactions(ids: Array(self.selectedMessages), reactions: mappedUpdatedReactions)
                    }
                } else {
                    if let selectionState = presentationInterfaceState.interfaceState.selectionState {
                        context.engine.messages.addMessageReactions(ids: Array(selectionState.selectedIds), reactions: [updateReaction])
                    } else {
                        context.engine.messages.addMessageReactions(ids: Array(self.selectedMessages), reactions: [updateReaction])
                    }
                }
                
                self.reactionOverlayContainer.dismissReactionSelection()
            }
            reactionContextNode.displayTail = true
            reactionContextNode.forceTailToRight = true
            reactionContextNode.forceDark = false
            self.reactionOverlayContainer.reactionContextNode = reactionContextNode
            self.reactionOverlayContainer.addSubnode(reactionContextNode)
            
            self.update(transition: .immediate)
        })
    }
    
    private func update(transition: ContainedViewLayoutTransition) {
        if let (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary, isMediaInputExpanded) = self.validLayout, let interfaceState = self.presentationInterfaceState {
            let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, additionalSideInsets: additionalSideInsets, maxHeight: maxHeight, isSecondary: isSecondary, transition: transition, interfaceState: interfaceState, metrics: metrics, isMediaInputExpanded: isMediaInputExpanded)
        }
    }
    
    override public func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat {
        self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary, isMediaInputExpanded)
        
        let panelHeight = defaultHeight(metrics: metrics)
        
        if self.presentationInterfaceState != interfaceState {
            self.presentationInterfaceState = interfaceState
        }
        if let actions = self.actions {
            self.deleteButton.isEnabled = false
            self.reportButton.isEnabled = false
            self.forwardButton.isImplicitlyDisabled = !actions.options.contains(.forward)
            
            if self.peerMedia {
                self.deleteButton.isEnabled = !actions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty
            } else {
                self.deleteButton.isEnabled = !actions.disableDelete
            }
            self.shareButton.isImplicitlyDisabled = actions.options.intersection(.forward).isEmpty || actions.options.intersection(.externalShare).isEmpty
            self.reportButton.isEnabled = !actions.options.intersection([.report]).isEmpty
            
            if self.peerMedia {
                self.deleteButton.isHidden = !self.deleteButton.isEnabled
            } else {
                self.deleteButton.isHidden = false
            }
            self.reportButton.isHidden = !self.reportButton.isEnabled
            
            if actions.setTag {
                if !actions.editTags.isEmpty {
                    self.tagButton.isHidden = true
                    self.tagEditButton.isHidden = false
                } else {
                    self.tagButton.isHidden = false
                    self.tagEditButton.isHidden = true
                }   
            } else {
                self.tagButton.isHidden = true
                self.tagEditButton.isHidden = true
            }
        } else {
            self.deleteButton.isEnabled = false
            self.deleteButton.isHidden = self.peerMedia
            self.reportButton.isEnabled = false
            self.reportButton.isHidden = true
            self.forwardButton.isImplicitlyDisabled = true
            self.shareButton.isImplicitlyDisabled = true
            self.tagButton.isHidden = true
            self.tagEditButton.isHidden = true
            self.tagButton.isHidden = true
            self.tagEditButton.isHidden = true
        }
        
        if self.reportButton.isHidden || (self.peerMedia && self.deleteButton.isHidden && self.reportButton.isHidden) {
            if let peer = interfaceState.renderedPeer?.peer as? TelegramChannel, case .broadcast = peer.info {
                self.reportButton.isHidden = false
            } else if self.peerMedia {
                self.deleteButton.isHidden = false
            }
        }
        
        var width = width
        if additionalSideInsets.right > 0.0 {
            width -= additionalSideInsets.right
        }
        
        var tagButton: HighlightableButtonNode?
        if !self.tagButton.isHidden {
            tagButton = self.tagButton
        } else if !self.tagEditButton.isHidden {
            tagButton = self.tagEditButton
        }
        
        let buttons: [HighlightableButtonNode]
        if self.reportButton.isHidden {
            if let tagButton {
                buttons = [
                    self.deleteButton,
                    tagButton,
                    self.shareButton,
                    self.forwardButton
                ]
            } else {
                buttons = [
                    self.deleteButton,
                    self.shareButton,
                    self.forwardButton
                ]
            }
        } else if !self.deleteButton.isHidden {
            if let tagButton {
                buttons = [
                    self.deleteButton,
                    self.reportButton,
                    tagButton,
                    self.shareButton,
                    self.forwardButton
                ]
            } else {
                buttons = [
                    self.deleteButton,
                    self.reportButton,
                    self.shareButton,
                    self.forwardButton
                ]
            }
        } else {
            if let tagButton {
                buttons = [
                    self.deleteButton,
                    self.reportButton,
                    tagButton,
                    self.shareButton,
                    self.forwardButton
                ]
            } else {
                buttons = [
                    self.deleteButton,
                    self.reportButton,
                    self.shareButton,
                    self.forwardButton
                ]
            }
        }
        
        let buttonSize = CGSize(width: 57.0, height: panelHeight)
        
        let availableWidth = width - leftInset - rightInset
        let spacing: CGFloat = floor((availableWidth - buttonSize.width * CGFloat(buttons.count)) / CGFloat(buttons.count - 1))
        var offset: CGFloat = leftInset
        for i in 0 ..< buttons.count {
            let button = buttons[i]
            if i == buttons.count - 1 {
                button.frame = CGRect(origin: CGPoint(x: width - rightInset - buttonSize.width, y: 0.0), size: buttonSize)
            } else {
                button.frame = CGRect(origin: CGPoint(x: offset, y: 0.0), size: buttonSize)
            }
            offset += buttonSize.width + spacing
        }
        
        transition.updateAlpha(node: self.separatorNode, alpha: isSecondary ? 1.0 : 0.0)
        self.separatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: panelHeight), size: CGSize(width: width, height: UIScreenPixel))
        
        if let reactionContextNode = self.reactionOverlayContainer.reactionContextNode, let tagButton {
            let isFirstTime = reactionContextNode.bounds.isEmpty
            
            let size = CGSize(width: width, height: maxHeight)
            let reactionsAnchorRect = tagButton.frame.offsetBy(dx: -54.0, dy: -(panelHeight - size.height) + 14.0)
            transition.updateFrame(node: reactionContextNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - size.height), size: size))
            reactionContextNode.updateLayout(size: size, insets: UIEdgeInsets(), anchorRect: reactionsAnchorRect, centerAligned: true, isCoveredByInput: false, isAnimatingOut: false, transition: transition)
            reactionContextNode.updateIsIntersectingContent(isIntersectingContent: true, transition: .immediate)
            if isFirstTime {
                reactionContextNode.animateIn(from: reactionsAnchorRect)
            }
        }
        
        return panelHeight
    }
    
    override public func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
        return defaultHeight(metrics: metrics)
    }
}