import Foundation
import TelegramPresentationData
import AccountContext
import Postbox
import TelegramCore
import SwiftSignalKit
import ContextUI
import ChatControllerInteraction
import Display
import UIKit
import UndoUI
import ShareController
import ChatQrCodeScreen
import ChatShareMessageTagView
import ReactionSelectionNode
import TopMessageReactions

func chatShareToSavedMessagesAdditionalView(_ chatController: ChatControllerImpl, reactionItems: [ReactionItem], correlationIds: [Int64]) -> (() -> UndoOverlayControllerAdditionalView?)? {
    if !chatController.presentationInterfaceState.isPremium {
        return nil
    }
    if correlationIds.count < 1 {
        return nil
    }
    return { [weak chatController] () -> UndoOverlayControllerAdditionalView? in
        guard let chatController else {
            return nil
        }
        return ChatShareMessageTagView(context: chatController.context, presentationData: chatController.presentationData, isSingleMessage: correlationIds.count == 1, reactionItems: reactionItems, completion: { [weak chatController] file, updateReaction in
            guard let chatController else {
                return
            }
            
            let _ = (chatController.context.account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId: chatController.context.account.peerId, threadId: nil), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, ignoreMessageIds: Set(), count: 45, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allNonRegular), orderStatistics: [])
            |> map { view, _, _ -> [EngineMessage.Id] in
                let messageIds = correlationIds.compactMap { correlationId in
                    return chatController.context.engine.messages.synchronouslyLookupCorrelationId(correlationId: correlationId)
                }
                if messageIds.isEmpty {
                    return []
                }
                
                let exactResult = view.entries.compactMap { entry -> EngineMessage.Id? in
                    if messageIds.contains(entry.message.id) {
                        return entry.message.id
                    } else {
                        return nil
                    }
                }
                if !exactResult.isEmpty {
                    return exactResult
                }
                
                return []
            }
            |> filter { !$0.isEmpty }
            |> take(1)
            |> timeout(5.0, queue: .mainQueue(), alternate: .single([]))
            |> deliverOnMainQueue).start(next: { [weak chatController] messageIds in
                guard let chatController else {
                    return
                }
                if !messageIds.isEmpty {
                    let _ = chatController.context.engine.messages.setMessageReactions(ids: messageIds, reactions: [updateReaction])
                    
                    var isBuiltinReaction = false
                    if case .builtin = updateReaction {
                        isBuiltinReaction = true
                    }
                    let presentationData = chatController.context.sharedContext.currentPresentationData.with { $0 }
                    chatController.present(UndoOverlayController(presentationData: presentationData, content: .messageTagged(context: chatController.context, isSingleMessage: messageIds.count == 1, customEmoji: file, isBuiltinReaction: isBuiltinReaction, customUndoText: presentationData.strings.Chat_ToastMessageTagged_Action), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { [weak chatController] action in
                        if (action == .info || action == .undo), let chatController {
                            let _ = (chatController.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: chatController.context.account.peerId))
                            |> deliverOnMainQueue).start(next: { [weak chatController] peer in
                                guard let chatController else {
                                    return
                                }
                                guard let peer else {
                                    return
                                }
                                guard let navigationController = chatController.navigationController as? NavigationController else {
                                    return
                                }
                                chatController.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: chatController.context, chatLocation: .peer(peer), forceOpenChat: true))
                            })
                            return false
                        }
                        return false
                    }), in: .current)
                }
            })
        })
    }
}

extension ChatControllerImpl {
    func openMessageShareMenu(id: EngineMessage.Id) {
        guard let messages = self.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(id), let message = messages.first else {
            return
        }

        let chatPresentationInterfaceState = self.presentationInterfaceState
        var warnAboutPrivate = false
        var canShareToStory = false
        if case .peer = chatPresentationInterfaceState.chatLocation, let channel = message.peers[message.id.peerId] as? TelegramChannel {
            if case .broadcast = channel.info {
                canShareToStory = true
            }
            if channel.addressName == nil {
                warnAboutPrivate = true
            }
        }
        let shareController = ShareController(context: self.context, subject: .messages(messages), updatedPresentationData: self.updatedPresentationData, shareAsLink: true)
        shareController.parentNavigationController = self.navigationController as? NavigationController
        
        if let message = messages.first, message.media.contains(where: { media in
            if media is TelegramMediaContact || media is TelegramMediaPoll {
                return true
            } else if let file = media as? TelegramMediaFile, file.isSticker || file.isAnimatedSticker || file.isVideoSticker {
                return true
            } else {
                return false
            }
        }) {
            canShareToStory = false
        }
        if message.text.containsOnlyEmoji {
            canShareToStory = false
        }
        
        if canShareToStory {
            shareController.shareStory = { [weak self] in
                guard let self else {
                    return
                }
                Queue.mainQueue().after(0.15) {
                    self.openStorySharing(messages: messages)
                }
            }
        }
        shareController.openShareAsImage = { [weak self] messages in
            guard let self else {
                return
            }
            self.present(ChatQrCodeScreen(context: self.context, subject: .messages(messages)), in: .window(.root))
        }
        shareController.dismissed = { [weak self] shared in
            if shared {
                self?.commitPurposefulAction()
            }
        }
        shareController.actionCompleted = { [weak self] in
            guard let self else {
                return
            }
            let content: UndoOverlayContent
            if warnAboutPrivate {
                content = .linkCopied(text: self.presentationData.strings.Conversation_PrivateMessageLinkCopiedLong)
            } else {
                content = .linkCopied(text: self.presentationData.strings.Conversation_LinkCopied)
            }
            self.present(UndoOverlayController(presentationData: self.presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
        }
        shareController.enqueued = { [weak self] peerIds, correlationIds in
            guard let self else {
                return
            }
          
            let _ = (self.context.engine.data.get(
                EngineDataList(
                    peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init)
                )
            )
            |> deliverOnMainQueue).startStandalone(next: { [weak self] peerList in
                guard let self else {
                    return
                }
                let peers = peerList.compactMap { $0 }
                let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
                let text: String
                var savedMessages = false
                if peerIds.count == 1, let peerId = peerIds.first, peerId == self.context.account.peerId {
                    text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many
                    savedMessages = true
                } else {
                    if peers.count == 1, let peer = peers.first {
                        var peerName = peer.id == self.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
                        peerName = peerName.replacingOccurrences(of: "**", with: "")
                        text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string
                    } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last {
                        var firstPeerName = firstPeer.id == self.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
                        firstPeerName = firstPeerName.replacingOccurrences(of: "**", with: "")
                        var secondPeerName = secondPeer.id == self.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
                        secondPeerName = secondPeerName.replacingOccurrences(of: "**", with: "")
                        text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string
                    } else if let peer = peers.first {
                        var peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
                        peerName = peerName.replacingOccurrences(of: "**", with: "")
                        text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(peers.count - 1)").string
                    } else {
                        text = ""
                    }
                }
                
                let reactionItems: Signal<[ReactionItem], NoError>
                if savedMessages {
                    reactionItems = tagMessageReactions(context: self.context, subPeerId: self.chatLocation.threadId.flatMap(EnginePeer.Id.init))
                } else {
                    reactionItems = .single([])
                }
                
                let _ = (reactionItems
                |> deliverOnMainQueue).startStandalone(next: { [weak self] reactionItems in
                    guard let self else {
                        return
                    }
                    
                    self.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, position: savedMessages ? .top : .bottom, animateInAsReplacement: !savedMessages, action: { [weak self] action in
                        if savedMessages, let self, action == .info {
                            let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
                            |> deliverOnMainQueue).start(next: { [weak self] peer in
                                guard let self, let peer else {
                                    return
                                }
                                guard let navigationController = self.navigationController as? NavigationController else {
                                    return
                                }
                                self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), forceOpenChat: true))
                            })
                        }
                        return false
                    }, additionalView: savedMessages ? chatShareToSavedMessagesAdditionalView(self, reactionItems: reactionItems, correlationIds: correlationIds) : nil), in: .current)
                })
            })
        }
        self.chatDisplayNode.dismissInput()
        self.present(shareController, in: .window(.root), blockInteraction: true)
    }
}