import Foundation
import UIKit
import SwiftSignalKit
import Postbox
import TelegramCore
import AsyncDisplayKit
import Display
import TelegramNotices
import ContextUI
import AccountContext
import ChatMessageItemView
import ChatMessageItemCommon
import AvatarNode
import UndoUI
import MessageUI
import PeerInfoUI
import ChatControllerInteraction

extension ChatControllerImpl: MFMessageComposeViewControllerDelegate {
    func openPhoneContextMenu(number: String, params: ChatControllerInteraction.LongTapParams) -> Void {
        guard let message = params.message, let contentNode = params.contentNode else {
            return
        }
        
        guard let messages = self.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(message.id) else {
            return
        }
        
        var updatedMessages = messages
        for i in 0 ..< updatedMessages.count {
            if updatedMessages[i].id == message.id {
                let message = updatedMessages.remove(at: i)
                updatedMessages.insert(message, at: 0)
                break
            }
        }
        
        let recognizer: TapLongTapOrDoubleTapGestureRecognizer? = nil// anyRecognizer as? TapLongTapOrDoubleTapGestureRecognizer
        let gesture: ContextGesture? = nil // anyRecognizer as? ContextGesture
        
        let source: ContextContentSource
//                if let location = location {
//                    source = .location(ChatMessageContextLocationContentSource(controller: self, location: messageNode.view.convert(messageNode.bounds, to: nil).origin.offsetBy(dx: location.x, dy: location.y)))
//                } else {
            source = .extracted(ChatMessageLinkContextExtractedContentSource(chatNode: self.chatDisplayNode, contentNode: contentNode))
//                }
        
        params.progress?.set(.single(true))
        
        let _ = (self.context.engine.peers.resolvePeerByPhone(phone: number)
        |> deliverOnMainQueue).start(next: { [weak self] peer in
            guard let self else {
                return
            }
            params.progress?.set(.single(false))
            
            let phoneNumber: String
            if let peer, case let .user(user) = peer, let phone = user.phone {
                phoneNumber = "+\(phone)"
            } else {
                phoneNumber = number
            }
            
            var items: [ContextMenuItem] = []
            items.append(
                .action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_AddToContacts, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
                    guard let self, let c else {
                        return
                    }
                    let basicData = DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [
                        DeviceContactPhoneNumberData(label: "", value: phoneNumber)
                    ])
                    let contactData = DeviceContactExtendedData(basicData: basicData, middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
                    
                    pushContactContextOptionsController(context: self.context, contextController: c, presentationData: self.presentationData, peer: nil, contactData: contactData, parentController: self, push: { [weak self] c in
                        self?.push(c)
                    })
                }))
            )
            items.append(.separator)
            if let peer {
                if peer.id == self.context.account.peerId {
                    
                } else {
                    items.append(
                        .action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_SendMessage, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MessageBubble"), color: theme.contextMenu.primaryColor) }, action: { [weak self]  _, f in
                            f(.default)
                            guard let self else {
                                return
                            }
                            self.openPeer(peer: peer, navigation: .chat(textInputState: nil, subject: nil, peekData: nil), fromMessage: nil)
                        }))
                    )
                    items.append(
                        .action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_TelegramVoiceCall, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Call"), color: theme.contextMenu.primaryColor) }, action: { [weak self]  _, f in
                            f(.default)
                            
                            guard let self else {
                                return
                            }
                            self.controllerInteraction?.callPeer(peer.id, false)
                        }))
                    )
                    items.append(
                        .action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_TelegramVideoCall, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/VideoCall"), color: theme.contextMenu.primaryColor) }, action: { [weak self]  _, f in
                            f(.default)
                            
                            guard let self else {
                                return
                            }
                            self.controllerInteraction?.callPeer(peer.id, true)
                        }))
                    )
                }
            } else {
                items.append(
                    .action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_InviteToTelegram, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Telegram"), color: theme.contextMenu.primaryColor) }, action: { [weak self]  _, f in
                        f(.default)
                        
                        guard let self else {
                            return
                        }
                        self.inviteToTelegram(numbers: [number])
                    }))
                )
            }
            if number.hasPrefix("+888") {
                
            } else {
                items.append(
                    .action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_CallViaCarrier, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/PhoneCall"), color: theme.contextMenu.primaryColor) }, action: { [weak self]  _, f in
                        f(.default)
                        
                        guard let self else {
                            return
                        }
                        self.openUrl("tel:\(phoneNumber)", concealed: false)
                    }))
                )
            }
            
            items.append(
                .action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_CopyNumber, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self]  _, f in
                    f(.default)

                    guard let self else {
                        return
                    }
                    
                    UIPasteboard.general.string = number

                    self.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: presentationData.strings.Conversation_PhoneCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
                }))
            )
            
            items.append(.separator)
            if let peer {
                let avatarSize = CGSize(width: 28.0, height: 28.0)
                let avatarSignal = peerAvatarCompleteImage(account: self.context.account, peer: peer, size: avatarSize)
                
                let subtitle = NSMutableAttributedString(string: self.presentationData.strings.Chat_Context_Phone_ViewProfile + " >")
                if let range = subtitle.string.range(of: ">"), let arrowImage = UIImage(bundleImageName: "Item List/InlineTextRightArrow") {
                    subtitle.addAttribute(.attachment, value: arrowImage, range: NSRange(range, in: subtitle.string))
                    subtitle.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: subtitle.string))
                }
                
                items.append(
                    .action(ContextMenuActionItem(text: peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), textLayout: .secondLineWithAttributedValue(subtitle), icon: { theme in return nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: avatarSignal), iconPosition: .left, action: { [weak self]  _, f in
                        f(.default)
                        
                        guard let self else {
                            return
                        }
                        self.openPeer(peer: peer, navigation: .info(ChatControllerInteractionNavigateToPeer.InfoParams(ignoreInSavedMessages: true)), fromMessage: nil)
                    }))
                )
            } else {
                let emptyAction: ((ContextMenuActionItem.Action) -> Void)? = nil
                items.append(
                    .action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_NotOnTelegram, textLayout: .multiline, textFont: .small, icon: { _ in return nil }, action: emptyAction))
                )
            }
            
            self.canReadHistory.set(false)
            
            let controller = ContextController(presentationData: self.presentationData, source: source, items: .single(ContextController.Items(content: .list(items))), recognizer: recognizer, gesture: gesture, disableScreenshots: false)
            controller.dismissed = { [weak self] in
                self?.canReadHistory.set(true)
            }
            
            self.window?.presentInGlobalOverlay(controller)
        })
    }
    
    private func inviteToTelegram(numbers: [String]) {
        if MFMessageComposeViewController.canSendText() {
            let composer = MFMessageComposeViewController()
            composer.messageComposeDelegate = self
            composer.recipients = Array(Set(numbers))
            let url = self.presentationData.strings.InviteText_URL
            let body = self.presentationData.strings.InviteText_SingleContact(url).string
            composer.body = body
            self.messageComposeController = composer
            if let window = self.view.window {
                window.rootViewController?.present(composer, animated: true)
            }
        }
    }
    
    @objc public func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
        self.messageComposeController = nil
        
        controller.dismiss(animated: true, completion: nil)
    }
}

final class ChatMessageLinkContextExtractedContentSource: ContextExtractedContentSource {
    let keepInPlace: Bool = false
    let ignoreContentTouches: Bool = true
    let blurBackground: Bool = true
    let adjustContentHorizontally = true
    
    private weak var chatNode: ChatControllerNode?
    private let contentNode: ContextExtractedContentContainingNode
    
    var shouldBeDismissed: Signal<Bool, NoError> {
        return .single(false)
    }
    
    init(chatNode: ChatControllerNode, contentNode: ContextExtractedContentContainingNode) {
        self.chatNode = chatNode
        self.contentNode = contentNode
    }
    
    func takeView() -> ContextControllerTakeViewInfo? {
        guard let chatNode = self.chatNode else {
            return nil
        }
        
        let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
        transition.updateAlpha(node: self.contentNode.contentNode, alpha: 1.0)
        
        return ContextControllerTakeViewInfo(containingItem: .node(self.contentNode), contentAreaInScreenSpace: chatNode.convert(chatNode.frameForVisibleArea(), to: nil))
    }
    
    func putBack() -> ContextControllerPutBackViewInfo? {
        guard let chatNode = self.chatNode else {
            return nil
        }
        
        let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
        transition.updateAlpha(node: self.contentNode.contentNode, alpha: 0.0, completion: { _ in
            self.contentNode.removeFromSupernode()
        })
        
        return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: chatNode.convert(chatNode.frameForVisibleArea(), to: nil))
    }
}