//
//  ChatViewController.swift
//  WoWonder
//
//  Created by Mac on 09/11/22.
//  Copyright © 2022 ScriptSun. All rights reserved.
//

import UIKit
import Async
import DropDown
import AVFoundation
import AVKit
import GoogleMaps
import WowonderMessengerSDK
import MobileCoreServices
import FileProvider
import CoreData
import IQKeyboardManagerSwift
import MapKit
import Toast_Swift
import SafariServices
import SDWebImage
import ContactsUI
import Stipop
import MediaPlayer

class ChatViewController: BaseVC {
    
    // MARK: - IBOutlets
    
    @IBOutlet weak var topVeiw: UIView!
    @IBOutlet weak var headerView: UIView!
    @IBOutlet weak var backButton: UIControl!
    @IBOutlet weak var userProfileImageView: UIImageView!
    @IBOutlet weak var userActiveImageView: UIImageView!
    @IBOutlet weak var userNameLabel: UILabel!
    @IBOutlet weak var userActiveStatusLabel: UILabel!
    @IBOutlet weak var videoCallButton: UIButton!
    @IBOutlet weak var audioCallButton: UIButton!
    @IBOutlet weak var moreButton: UIButton!
    @IBOutlet weak var mediaButton: UIButton!
    @IBOutlet weak var stickerButton: SPUIButton!
    @IBOutlet weak var audioRecordButton: RecordButton!
    @IBOutlet weak var sendButton: UIButton!
    @IBOutlet weak var chatTableView: UITableView!
    @IBOutlet weak var messageTextView: EmojiTextView!
    @IBOutlet weak var bottomView: UIView!
    @IBOutlet weak var pinMessageView: UIView!
    @IBOutlet weak var pinMessageLabel: UILabel!
    @IBOutlet weak var lastPinMessageLabel: UILabel!
    @IBOutlet weak var pinSideView: UIView!
    @IBOutlet weak var replyMessageView: UIView!
    @IBOutlet weak var replyMessageViewHeight: NSLayoutConstraint!
    @IBOutlet weak var replyBorderView: UIView!
    @IBOutlet weak var replyUserNameLabel: UILabel!
    @IBOutlet weak var replyMessageLabel: UILabel!
    @IBOutlet weak var replyImageView: UIImageView!
    @IBOutlet weak var replyCancelButton: UIButton!
    @IBOutlet weak var audioRecordView: RecordView!
    @IBOutlet weak var tableViewBottom: NSLayoutConstraint!
    @IBOutlet weak var bgImage: UIImageView!
    @IBOutlet weak var sendView: UIView!
    @IBOutlet weak var audioRecordSendView: UIView!
    @IBOutlet weak var audioRecordSliderView: UISlider!
    @IBOutlet weak var audioRecordPlayButton: UIButton!
    @IBOutlet weak var audioRecordDeleteButton: UIButton!
    @IBOutlet weak var audioRecordSendButton: UIButton!
    @IBOutlet weak var audioRecordSendViewHeight: NSLayoutConstraint!
    @IBOutlet weak var unBlockView: UIView!
    @IBOutlet weak var unBlockButton: UIButton!
    @IBOutlet weak var sendMessageView: UIView!
    
    // MARK: - Properties
    
    var imagePickerMediaType: ImagePickerMediaType = .IMAGE
    let socketHelper = SocketHelper.shared
    var limit = 1000
    var recipientID = ""
    private var imagePicker = UIImagePickerController()
    private var scrollStatus = true
    private var isReplyStatus = false
    private var sendMessageAudioPlayer: AVAudioPlayer?
    var audioRecoderPlayer : AVAudioPlayer!
    private var toneStatus = false
    private var replyMessageID = ""
    private var isPagination = false
    private var offset: Int = 50
    var audioRecorderHelper: AudioRecorderHelper!
    var audioFileURL: URL?
    var isColor = ""
    var chatModel: Chats?
    var isSendRecordAudio = false
    var audioRecodeTimer: Timer?
    var userData: UserData?
    var messageArray: [MessageModel] = []
    var pinMessageArray: [MessageModel] = []
    var favMessageArray: [MessageModel] = []
    private var messagesArray = [Messages]() {
        didSet {
            self.chatModel?.addToMessages(NSSet(array: self.messagesArray))
            self.chatModel?.save()
            guard let lastMsg = self.messagesArray.last, let user = self.chatModel?.getFirstChatUser()?.user else { return }
            user.last_message = lastMsg
            user.save()
        }
    }
    var saveDataArray: [Chats] = []
    
    // MARK: - View Life Cycles
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.initialConfig()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        self.navigationController?.navigationBar.isHidden = true
        AudioPlayerHelper.shared.delegate = self
        self.setUpUI()
        self.setUpUnBlockView(isBlocked: false)
        self.fetchData()
        self.fetchReciverUserProfile()
        self.pinMessageView.isHidden = true
        if let chat_id = self.chatModel?.chat_id {
            self.getPinMessages(chat_id: chat_id)
            self.getFavMessages(chat_id: chat_id)
        }
        self.replyMessageViewHeight.constant = 0
        self.replyMessageView.isHidden = true
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        self.removeObserver()
        IQKeyboardManager.shared.isEnabled = true
        self.audioRecoderPlayer?.pause()
        self.audioRecodeTimer?.invalidate()
        self.audioRecodeTimer = nil
        self.audioRecordPlayButton.setImage(UIImage(named: "icon_play_vector"), for: .normal)
        AudioPlayerHelper.shared.stopAudioPlayer()
        
        self.socketHelper.socket.off("typing")
        self.socketHelper.socket.off("lastseen")
        self.socketHelper.socket.off("recording")
        self.socketHelper.socket.off("register_reaction")
    }
    
    // MARK: - Selectors
    
    // Back Button Action
    @IBAction func backButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        self.navigationController?.popViewController(animated: true)
    }
    
    // User Profile Button Action
    @IBAction func userProfileButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if let newVC = R.storyboard.dashboard.userProfileViewController() {
            newVC.user_id = self.userData?.user_id ?? ""
            newVC.user_data = self.userData
            newVC.messageArray = self.messagesArray
            self.navigationController?.pushViewController(newVC, animated: true)
        }
    }
    
    // Video Call Button Action
    @IBAction func videoCallButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if userData?.is_blocked ?? false {
            self.view.makeToast("You can't message him or call him in this chat because you blocked this account")
            return
        }
        if let user = self.userData {
            if AppInstance.instance.siteSetting?.agora_chat_video == "1" {
                self.createAgoraCall(recipient_id: user.user_id ?? "", call_Type: "video", user: user)
            } else if AppInstance.instance.siteSetting?.twilio_video_chat == "1" {
                self.createTwilioCall(recipient_id: user.user_id ?? "", call_Type: "video", user: user)
            }
        }
    }
    
    // Audio Call Button Action
    @IBAction func audioCallButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if userData?.is_blocked ?? false {
            self.view.makeToast("You can't message him or call him in this chat because you blocked this account")
            return
        }
        if let user = self.userData {
            if AppInstance.instance.siteSetting?.agora_chat_video == "1" {
                self.createAgoraCall(recipient_id: user.user_id ?? "", call_Type: "audio", user: user)
            } else if AppInstance.instance.siteSetting?.twilio_video_chat == "1" {
                self.createTwilioCall(recipient_id: user.user_id ?? "", call_Type: "audio", user: user)
            }
        }
    }
    
    // More Button Action
    @IBAction func moreButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if let newVC = R.storyboard.chat.moreOptionViewController() {
            newVC.modalPresentationStyle = .custom
            newVC.transitioningDelegate = self
            newVC.delegate = self
            newVC.reciverUserData = self.userData
            newVC.isFavourite = self.favMessageArray.count != 0
            self.present(newVC, animated: true)
        }
    }
    
    // Media Button Action
    @IBAction func mediaButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        let newVC = self.storyboard?.instantiateViewController(withIdentifier: "ChatMediaOptionVC") as! ChatMediaOptionVC
        newVC.modalPresentationStyle = .custom
        newVC.transitioningDelegate = self
        newVC.delegate = self
        self.present(newVC, animated: true)
    }
    
    // Emoji Button Action
    @IBAction func emojiButtonAction(_ sender: UIButton) {
        self.messageTextView.isEmojiKeyboard = true
        self.messageTextView.becomeFirstResponder()
    }
    
    // Send Button Action
    @IBAction func sendButtonAction(_ sender: UIButton) {
        if chatModel?.chat_id == nil {
            if messageTextView.text != "" {
                self.sendMessage(text: messageTextView.text, lat: 0, lng: 0)
            }
        } else {
            self.socketHelper.emit_private_message(to_id: self.recipientID, from_id: AppInstance.instance._sessionId, username: AppInstance.instance.userProfile?.username ?? "", msg: self.messageTextView.text, color: self.isColor == "" ? "#ffffff" : self.isColor, message_reply_id: self.replyMessageID == "" ? "0" : self.replyMessageID, story_id: "", lat: "", lng: "") {
                self.view.resignFirstResponder()
                if self.toneStatus {
                    self.playSendMessageSound()
                } else {
                    
                }
                self.messageTextView.text = ""
                self.setSendButton()
                if self.isReplyStatus {
                    self.hideReplyMessageView()
                }
                self.fetchData()
            }
        }
    }
    
    // Audio Record Play Button Action
    @IBAction func audioRecordPlayButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if self.audioRecoderPlayer.isPlaying {
            self.audioRecoderPlayer?.pause()
            self.audioRecodeTimer?.invalidate()
            self.audioRecodeTimer = nil
            self.audioRecordPlayButton.setImage(UIImage(named: "icon_play_vector"), for: .normal)
        } else {
            self.audioRecoderPlayer?.play()
            self.audioRecodeTimer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.updatePlaybackProgress), userInfo: nil, repeats: true)
            self.audioRecordPlayButton.setImage(UIImage(named: "icon_pause_vector"), for: .normal)
        }
    }
    
    @IBAction func audioRecordSliderValueChanged(_ sender: UISlider) {
        self.audioRecoderPlayer?.currentTime = TimeInterval(sender.value)
    }
    
    @objc func updatePlaybackProgress() {
        self.audioRecordSliderView.value = Float(self.audioRecoderPlayer.currentTime)
    }
    
    // Audio Record Delete Button Action
    @IBAction func audioRecordDeleteButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        self.hideAudioRecordView()
    }
    
    // Audio Record Send Button Action
    @IBAction func audioRecordSendButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if self.isSendRecordAudio {
            if let audioFileURL = self.audioFileURL {
                let audioData = try? Data(contentsOf: audioFileURL)
                self.sendSelectedData(audioData: audioData, imageData: nil, videoData: nil, imageMimeType: nil, VideoMimeType: nil, audioMimeType: audioData?.mimeType, Type: "audio", fileData: nil, fileExtension: nil, FileMimeType: nil)
            }
        }
        self.isSendRecordAudio = false
        self.hideAudioRecordView()
    }
    
    // Pin Message Button Action
    @IBAction func pinMessageButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if let newVC = R.storyboard.chat.pinnedAndFavouriteMessageVC() {
            newVC.headerTitle = "Pinned Message"
            newVC.chatModel = self.chatModel
            newVC.isPinnedMessages = true
            newVC.messagesArray = self.pinMessageArray
            self.navigationController?.pushViewController(newVC, animated: true)
        }
    }
    
    // Cancel Reply Button Action
    @IBAction func cancelReplyButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        self.hideReplyMessageView()
    }
    
    // UnBlock Button Action
    @IBAction func unBlockButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if self.userData?.is_blocked ?? false {
            self.blockUser(block_action: "un-block")
        } else {
            self.blockUser(block_action: "block")
        }
    }
    
    // MARK: - Helper Functions
    
    // Initial Config
    func initialConfig() {
        self.setData()
        self.setUpUI()
        self.setUpMessageTextView()
        self.registerCell()
        self.setObserver()
        self.setUpAudioRecordView()
        IQKeyboardManager.shared.isEnabled = false
        self.stickerButton.setUser(SPUser(userID: AppInstance.instance._userId), viewType: .picker)
        self.stickerButton.delegate = self
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
        self.view.addGestureRecognizer(tapGesture)
        let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressed))
        self.chatTableView.addGestureRecognizer(longPressRecognizer)
        if chatModel?.chat_id == nil {
            fetchChatData()
        }
        self.getScoketResposeData()
    }
    
    func getScoketResposeData() {
        
        self.socketHelper.on_private_message_page { data in
            print(data)
        }
        
        self.socketHelper.on_typing { data in
            print("typing >>>>> ", data)
            let result = data.first as? [String: Any]
            if self.recipientID == "\((result?["sender_id"] as? Int) ?? 0)" {
                if let isTyping  = result?["is_typing"] as? Int, isTyping == 200 {
                    self.userActiveStatusLabel.text = "Typping..."
                } else {
                    self.setData()
                }
            }
        }
        
        self.socketHelper.on_recording { data in
            print("recording >>>>> ", data)
            let result = data.first as? [String: Any]
            if self.recipientID == "\((result?["sender_id"] as? Int) ?? 0)" {
                if let isRecording  = result?["is_recording"] as? Int, isRecording == 200 {
                    self.userActiveStatusLabel.text = "Recording..."
                } else {
                    self.setData()
                }
            }
        }
                
        self.socketHelper.on_private_message { data in
            print("private_message >>>>> ", data)
            let result = data.first as? [String: Any]
            if self.recipientID == "\((result?["sender"] as? Int) ?? 0)" {
                self.fetchData()
            }
        }
        
        self.socketHelper.on_lastseen { data in
            print("Last Seen >>>>> ", data)
            let result = data.first as? [String: Any]
            if self.recipientID == "\((result?["user_id"] as? Int) ?? 0)" {
                    self.fetchData()
            }
        }
        
        self.socketHelper.on_register_reaction { data in
            print("Register Reaction >>>>> ", data)
            self.fetchData()
        }
        
        self.socketHelper.on_seen_messages { data in
            print("Seen Messages >>>>> ", data)
        }
        
        self.socketHelper.on_page_message { data in
            print("page_message >>>>> ", data)
        }
        
        self.socketHelper.on_user_status_change { data in
            print("user_status_change >>>>>", data)
        }
        
    }
    
    func getChatDataFromUserId() {
        if self.saveDataArray.count == 0 {
            self.messagesArray = []
            self.chatTableView.reloadData()
            return
        }
        for user in self.saveDataArray {
            guard let object = user.getChatUsers().first?.user else { return }
            if object.user_id == self.recipientID {
                self.chatModel = user
                self.fetchData()
            }
        }
    }
    
    func fetchChatData() {
        let chats = Chats.getChats()
        if !chats.isEmpty {
            self.saveDataArray = chats
            self.getUserList { [weak self] (response) in
                guard let self = self else { return }
                guard let list = response.data else {
                    return
                }
                for user in list {
                    if let chatUser = ChatUsers.getChatUserByUserID(user.user_id ?? "") {
                        chatUser.updateUser(user)
                    } else {
                        let localChat = Chats(user: user)
                        localChat.save()
                    }
                }
                self.saveDataArray = Chats.getChats()
                self.getChatDataFromUserId()
            }
        } else {
            self.saveDataArray = []
            self.getUserList { model in
                Async.main({
                    self.dismissProgressDialog {
                        guard let data = model.data else {
                            return
                        }
                        for item in data {
                            if let chat = Chats.getChatByUserID(item.user_id ?? "") {
                                self.saveDataArray.append(chat)
                            } else {
                                let chat = Chats(user: item)
                                chat.save()
                                self.saveDataArray.append(chat)
                            }
                        }
                        self.getChatDataFromUserId()
                    }
                })
            }
        }
    }
    
    // Set Data
    func setData() {
        let url = URL(string: chatModel?.getChatUsers().first?.user?.avatar_url ?? userData?.avatar ?? "")
        let indicator = SDWebImageActivityIndicator.medium
        self.userProfileImageView.sd_imageIndicator = indicator
        DispatchQueue.global(qos: .userInteractive).async {
            self.userProfileImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "ic_No_images"))
        }
        self.userNameLabel.text = chatModel?.name ?? userData?.name ?? ""
        if userData?.lastseen_status == "on" {
            self.userActiveStatusLabel.text = "Online"
            self.userActiveImageView.isHidden = false
        } else {
            self.userActiveStatusLabel.text = "Last Seen " + (self.userData?.lastseen?.getLastSeenString(replace: false) ?? "")
            self.userActiveImageView.isHidden = true
        }
    }
    
    // SetUp UI
    func setUpUI() {
        let UserDefa = UserDefaults.standard
        let colorWallpaper = UserDefa.value(forKey: "colorWallpaper")
        let imgWallpaper = UserDefa.value(forKey: "imgWallpaper")
        if colorWallpaper != nil {
            self.bgImage.isHidden = true
            self.chatTableView.backgroundColor = UIColor(hex: colorWallpaper as! String)
        } else if imgWallpaper != nil {
            self.bgImage.isHidden = false
            self.chatTableView.backgroundColor = UIColor.clear
            self.bgImage.image = UIImage(data: imgWallpaper as! Data)
        } else {
            self.bgImage.isHidden = true
            // self.chatTableView.backgroundColor = UIColor.hexStringToUIColor(hex: "#F3F3F3")
        }
        let objColor = UserDefaults.standard.value(forKey: "ColorTheme")
        self.isColor = objColor as? String ?? ""
        if isColor != "" {
            self.backButton.tintColor = UIColor(hex: isColor)
            self.videoCallButton.tintColor = UIColor(hex: isColor)
            self.audioCallButton.tintColor = UIColor(hex: isColor)
            self.moreButton.tintColor = UIColor(hex: isColor)
            self.pinSideView.backgroundColor = UIColor(hex: isColor)
            self.pinMessageLabel.textColor = UIColor(hex: isColor)
            self.sendButton.tintColor = UIColor(hex: isColor)
            self.mediaButton.backgroundColor = UIColor(hex: isColor)
            self.userProfileImageView.borderColorV = UIColor(hex: isColor)
            self.userProfileImageView.borderWidthV = 1
            self.audioRecordPlayButton.backgroundColor = UIColor(hex: isColor)
            self.audioRecordDeleteButton.backgroundColor = UIColor(hex: isColor)
            self.audioRecordSendButton.backgroundColor = UIColor(hex: isColor)
            self.audioRecordSliderView.minimumTrackTintColor = UIColor(hex: isColor)
            self.audioRecordSliderView.maximumTrackTintColor = UIColor(hex: isColor).withAlphaComponent(0.34)
            self.audioRecordSliderView.setThumbImage(UIImage(named: "left_slider_thumb"), for: .normal)
            self.audioRecordSliderView.setThumbImage(UIImage(named: "left_slider_thumb"), for: .highlighted)
            self.unBlockButton.backgroundColor = UIColor(hex: isColor)
        }
    }
    
    // SetUp Message TextView
    func setUpMessageTextView() {
        self.messageTextView.delegate = self
        self.messageTextView.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        self.messageTextView.addPlaceholder("Write your message", with: UIColor.text_color_in_between)
        self.setSendButton()
    }
    
    // SetUp Audio Record View
    func setUpAudioRecordView() {
        self.audioRecordView.durationTimerColor = .red
        self.audioRecordButton.recordView = self.audioRecordView
        self.audioRecordView.delegate = self
        self.audioRecordView.isHidden = true
        self.audioRecordSendView.isHidden = true
        self.audioRecordSendViewHeight.constant = 0
        self.audioRecorderHelper = AudioRecorderHelper()
        self.audioRecorderHelper.delegate = self
    }
    
    // SetUp UnBlock View
    func setUpUnBlockView(isBlocked: Bool) {
        self.unBlockView.isHidden = !isBlocked
        self.sendMessageView.isHidden = isBlocked
    }
    
    // SetUp Pin Message View
    func setUpPinMessageView(pinMessageArray: [MessageModel]) {
        if pinMessageArray.count == 0 {
            self.pinMessageView.isHidden = true
        } else {
            self.pinMessageView.isHidden = false
            if let object = pinMessageArray.last {
                if object.type == "right_text" || object.type == "left_text" {
                    if (Double(object.lat ?? "0.0") ?? 0.0) > 0.0 || Double(object.lng ?? "0.0") ?? 0.0 > 0.0 {
                        self.lastPinMessageLabel.text = "Last Pin Message: Location"
                    } else {
                        self.lastPinMessageLabel.text = "Last Pin Message: " + (object.text ?? "")
                    }
                } else if object.type == "right_image" || object.type == "left_image" {
                    self.lastPinMessageLabel.text = "Last Pin Message: Image"
                } else if object.type == "right_video" || object.type == "left_video" {
                    self.lastPinMessageLabel.text = "Last Pin Message: Video"
                } else if object.type == "right_file" || object.type == "left_file" {
                    self.lastPinMessageLabel.text = "Last Pin Message: File"
                } else if object.type == "right_audio" || object.type == "left_audio" {
                    self.lastPinMessageLabel.text = "Last Pin Message: Audio"
                } else if object.type == "right_contact" || object.type == "left_contact" {
                    self.lastPinMessageLabel.text = "Last Pin Message: Contact"
                } else if object.type == "right_sticker" || object.type == "left_sticker" {
                    self.lastPinMessageLabel.text = "Last Pin Message: Sticker"
                } else if object.type == "right_gif" || object.type == "left_gif" {
                    self.lastPinMessageLabel.text = "Last Pin Message: Gif"
                }
            }
        }
    }
    
    // SetUpReplyMessageView
    func setUpReplyMessageView(message: Messages) {
        if message.from_id == AppInstance.instance._userId {
            self.replyUserNameLabel.text = "You"
        } else {
            self.replyUserNameLabel.text = self.userData?.name
        }
        self.replyImageView.isHidden = false
        if message.type == "right_text" || message.type == "left_text" {
            if (Double(message.lat ?? "0.0") ?? 0.0) > 0.0 || Double(message.lng ?? "0.0") ?? 0.0 > 0.0 {
                self.replyImageView.image = UIImage(named: "chat_media_location")
                self.replyMessageLabel.text = "Location"
            } else {
                self.replyImageView.isHidden = true
                let text = self.decryptionAESModeECB(messageData: message._text.htmlAttributedString ?? "", key: message._time) ?? ""
                self.replyMessageLabel.text = text
            }
        } else if message.type == "right_image" || message.type == "left_image" {
            let imageUrl = URL(string: message.media ?? "")
            let indicator = SDWebImageActivityIndicator.medium
            self.replyImageView.sd_imageIndicator = indicator
            DispatchQueue.global(qos: .userInteractive).async {
                self.replyImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
            }
            self.replyMessageLabel.text = "Image"
        } else if message.type == "right_video" || message.type == "left_video" {
            if let videoURL = URL(string: message.media ?? "") {
                self.replyImageView.image = UIImage(named: "")
                self.generateThumbnail(from: videoURL, completion: { image in
                    self.replyImageView.image = image
                })
            }
            self.replyMessageLabel.text = "Video"
        } else if message.type == "right_file" || message.type == "left_file" {
            self.replyImageView.image = UIImage(named: "chat_media_file")
            self.replyMessageLabel.text = "File"
        } else if message.type == "right_audio" || message.type == "left_audio" {
            self.replyImageView.image = UIImage(named: "chat_media_music")
            self.replyMessageLabel.text = "Audio"
        } else if message.type == "right_contact" || message.type == "left_contact" {
            self.replyImageView.image = UIImage(named: "chat_media_contact")
            self.replyMessageLabel.text = "Contact"
        } else if message.type == "right_sticker" || message.type == "left_sticker" {
            let stickerUrl = URL(string: message.media ?? "")
            let indicator = SDWebImageActivityIndicator.medium
            self.replyImageView.sd_imageIndicator = indicator
            DispatchQueue.global(qos: .userInteractive).async {
                self.replyImageView.sd_setImage(with: stickerUrl, placeholderImage: UIImage(named: ""))
            }
            self.replyMessageLabel.text = "Sticker"
        } else if message.type == "right_gif" || message.type == "left_gif" {
            let gifUrl = URL(string: message.stickers ?? "")
            let indicator = SDWebImageActivityIndicator.medium
            self.replyImageView.sd_imageIndicator = indicator
            DispatchQueue.global(qos: .userInteractive).async {
                self.replyImageView.sd_setImage(with: gifUrl)
            }
            self.replyMessageLabel.text = "Gif"
        }
        self.isReplyStatus = true
        self.replyMessageID = message._message_id
        self.showReplyMessageView()
    }
    
    // Swipe To Reply
    private func showReplyMessageView() {
        self.replyMessageView.isHidden = false
        self.replyMessageViewHeight.constant = 84
        UIView.animate(withDuration: 0.5) {
            self.view.layoutIfNeeded()
        }
    }
    
    private func hideReplyMessageView() {
        self.replyMessageID = ""
        self.isReplyStatus = false
        self.replyMessageViewHeight.constant = 0
        UIView.animate(withDuration: 0.5, animations: {
            self.view.layoutIfNeeded()
        }) { _ in
            self.replyMessageView.isHidden = true
        }
    }
    
    // Fetch Data
    private func fetchData() {
        guard let localChat = self.chatModel else {
            self.fetchChatData()
            return
        }
        let localMessages = Messages.getMessagesByChatID(localChat.chat_id ?? "", limit: self.limit)
        if !localMessages.isEmpty {
            self.messagesArray = localMessages // .reversed()
            self.chatTableView.reloadData()
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                self.chatTableView.scrollToLastRow(animated: false)
                self.view.layoutIfNeeded()
                self.chatTableView.layoutIfNeeded()
            }
        }
        self.sendAPIRequestMessages(limit: self.limit) { [weak self] (list) in
            guard let self = self else { return }
            for message in list {
                if let msg = Messages.getMessageByID(message.id ?? "") {
                    msg.chat_id = localChat.chat_id ?? ""
                    msg.updateMessage(message: message)
                } else {
                    let _ = Messages.init(chat_id: localChat.chat_id ?? "", message: message)
                }
            }
            let array = Messages.getMessagesByChatID(localChat.chat_id ?? "", limit: self.limit)
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                self.messagesArray = array //.reversed()
                self.chatTableView.reloadData()
                if self.messagesArray.count != 0 {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                        self.chatTableView.scrollToLastRow(animated: false)
                        self.view.layoutIfNeeded()
                        self.chatTableView.layoutIfNeeded()
                    }
                }
            }
            if self.messagesArray.last?._seen == "0" {
                self.socketHelper.emit_seen_messages(recipient_id: self.recipientID, user_id: AppInstance.instance._sessionId, current_user_id: AppInstance.instance._userId)
            }
        }
    }
    
    // Set Observer
    func setObserver() {
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    // Remove Observer
    func removeObserver() {
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    // Keyboard Will Show
    @objc func keyboardWillShow(_ notification: NSNotification) {
        let userInfo = notification.userInfo!
        let bottom = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height
        self.tableViewBottom.constant = bottom - self.view.safeAreaBottom
        let duration: TimeInterval = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
        UIView.animate(withDuration: duration) {
            if self.messagesArray.count != 0 {
                self.chatTableView.scrollToLastRow(animated: false)
            }
            self.view.layoutIfNeeded()
        }
    }
    
    // Keyboard Will Hide
    @objc func keyboardWillHide(_ notification: NSNotification) {
        let userInfo = notification.userInfo!
        self.tableViewBottom.constant = 0
        let duration: TimeInterval = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
        UIView.animate(withDuration: duration) { self.view.layoutIfNeeded() }
    }
    
    func registerCell() {
        self.chatTableView.delegate = self
        self.chatTableView.dataSource = self
        if #available(iOS 15.0, *) {
            UITableView.appearance().isPrefetchingEnabled = false
        }
        self.chatTableView.register(UINib(resource: R.nib.leftTextTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftTextTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightTextTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightTextTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightImageTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightImageTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftImageTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftImageTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftDocumentTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftDocumentTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightDocumentTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightDocumentTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftVideoTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftVideoTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightVideoTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightVideoTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightGifTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightGifTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftGifTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftGifTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftLocationTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftLocationTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightLocationTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightLocationTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftAudioTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftAudioTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightAudioTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightAudioTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftContactTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftContactTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightContactTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightContactTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightStickerCell), forCellReuseIdentifier: R.reuseIdentifier.rightStickerCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftStickerCell), forCellReuseIdentifier: R.reuseIdentifier.leftStickerCell.identifier)
    }
    
    // Set Send Button
    func setSendButton() {
        if self.messageTextView.text == "" {
            self.socketHelper.emit_typing_done(recipient_id: self.recipientID, user_id: AppInstance.instance._sessionId)
            self.sendButton.isHidden = true
            self.stickerButton.isHidden = false
            self.audioRecordButton.isHidden = false
        } else {
            self.socketHelper.emit_typing(recipient_id: self.recipientID, user_id: AppInstance.instance._sessionId)
            self.sendButton.isHidden = false
            self.stickerButton.isHidden = true
            self.audioRecordButton.isHidden = true
        }
    }
    
    @objc func handleTap(_ gesture: UITapGestureRecognizer) {
        self.view.endEditing(true)
    }
    
    // TableView longPressed Click
    @objc func longPressed(sender: UILongPressGestureRecognizer) {
        let objSender = sender.location(in: self.chatTableView)
        let indexPath = self.chatTableView.indexPathForRow(at: objSender)
        if indexPath != nil {
            let objCopyMessageArray = self.messagesArray[indexPath?.row ?? 0]
            if let newVC = R.storyboard.chat.messageOptionViewController() {
                newVC.modalPresentationStyle = .custom
                newVC.transitioningDelegate = self
                newVC.delegate = self
                newVC.indexPath = indexPath ?? IndexPath()
                if objCopyMessageArray.type == "right_text" || objCopyMessageArray.type == "left_text" {
                    if (Double(objCopyMessageArray.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objCopyMessageArray.lng ?? "0.0") ?? 0.0 > 0.0 {
                        newVC.isCopy = false
                    } else {
                        newVC.isCopy = true
                    }
                } else {
                    newVC.isCopy = false
                }
                newVC.message = objCopyMessageArray
                self.present(newVC, animated: true)
            }
        }
    }
    
}

// MARK: - Extensions

// MARK: Api Call
extension ChatViewController {
    
    // Get User Messages Api
    private func sendAPIRequestMessages(limit: Int, afterMsgId: String? = nil, beforeMsgId: String? = nil, messageId: String? = nil, _ completion: @escaping ([MessageModel]) -> Void) {
        let userId = AppInstance.instance._userId
        let sessionID = AppInstance.instance._sessionId
        Async.background {
            ChatManager.instance.getUserMessages(user_id: userId, session_Token: sessionID, receipent_id: self.recipientID, limit: limit, afterMsgId: afterMsgId, beforeMsgId: beforeMsgId, messageId: messageId) { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.messageArray = success?.messages ?? []
                            completion(success?.messages ?? [])
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            }
        }
    }
    
    // Get User List
    func getUserList(_ completion: @escaping (UserModelResponse) -> Void) {
        let userID = AppInstance.instance._userId
        Async.background {
            GetUserListManager.instance.getUserList(user_id: userID, session_Token: AppInstance.instance._sessionId) { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            guard let success = success else { return }
                            completion(success)
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            }
        }
    }
    
    // Pin Message Api Call
    private func pinMessageApi(message_id: String, pin: String, chat_id: String) {
        Async.background {
            ChatManager.instance.pinMessage(message_id: message_id, pin: pin, chat_id: chat_id, completionBlock: { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            print(success?.message ?? "")
                            if let chat_id = self.chatModel?.chat_id {
                                self.getPinMessages(chat_id: chat_id)
                                self.getFavMessages(chat_id: chat_id)
                            }
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            })
        }
    }
    
    // Get Pin Message Api Call
    private func getPinMessages(chat_id: String) {
        self.pinMessageArray = []
        Async.background {
            ChatManager.instance.getPinMessage(chat_id: chat_id, completionBlock: { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.pinMessageArray = success?.data ?? []
                            self.setUpPinMessageView(pinMessageArray: self.pinMessageArray)
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            })
        }
    }
    
    // Fav Message Api Call
    private func favMessageApi(message_id: String, fav: String, chat_id: String) {
        Async.background {
            ChatManager.instance.favMessage(message_id: message_id, fav: fav, chat_id: chat_id, completionBlock: { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            print(success?.message ?? "")
                            if let chat_id = self.chatModel?.chat_id {
                                self.getPinMessages(chat_id: chat_id)
                                self.getFavMessages(chat_id: chat_id)
                            }
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            })
        }
    }
    
    // Get Pin Message Api Call
    private func getFavMessages(chat_id: String) {
        self.favMessageArray = []
        Async.background {
            ChatManager.instance.getFavMessage(chat_id: chat_id, completionBlock: { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.favMessageArray = success?.data ?? []
                            self.chatTableView.reloadData()
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            })
        }
    }
    
    // Delete Message Api Call
    private func deleteMessage(messageID: String, indexPath: Int) {
        let sessionID = AppInstance.instance._sessionId
        Async.background {
            ChatManager.instance.deleteChatMessage(messageId: messageID, session_Token: sessionID, completionBlock: { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            if let chat_id = self.chatModel?.chat_id {
                                if self.messagesArray[indexPath].pin == "yes" {
                                    self.pinMessageApi(message_id: self.messagesArray[indexPath]._message_id, pin: "no", chat_id: chat_id)
                                }
                                if self.messagesArray[indexPath].fav == "yes" {
                                    self.favMessageApi(message_id: self.messagesArray[indexPath]._message_id, fav: "no", chat_id: chat_id)
                                }
                            }
                            let appDelegate = (UIApplication.shared.delegate) as? AppDelegate
                            let context = appDelegate?.persistentContainer.viewContext
                            context?.delete(self.messagesArray[indexPath])
                            do {
                                try context?.save()
                            } catch {
                                print("failed so save data after deleting object")
                            }
                            self.messagesArray.remove(at: indexPath)
                            self.chatTableView.reloadData()
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            })
        }
    }
    
    // Delete Chat
    func deleteChat(user_id: String) {
        Async.background {
            GetUserListManager.instance.deleteChat(user_id: user_id) { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            print(success?.message ?? "")
                            self.view.makeToast(success?.message)
                            guard let chat_id = self.chatModel?.chat_id else { return }
                            let appDelegate = (UIApplication.shared.delegate) as? AppDelegate
                            let context = appDelegate?.persistentContainer.viewContext
                            let predicate = NSPredicate(format: "%K == %@", #keyPath(Messages.chat_id), chat_id)
                            let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Messages")
                            fetchRequest.predicate = predicate
                            let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
                            do {
                                try context?.execute(deleteRequest)
                                try context?.save()
                            } catch {
                                print("error >>>>> ", error.localizedDescription)
                            }
                            let userPredicate = NSPredicate(format: "%K == %@", #keyPath(Chats.chat_id), chat_id)
                            let userFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Chats")
                            userFetchRequest.predicate = userPredicate
                            let userDeleteRequest = NSBatchDeleteRequest(fetchRequest: userFetchRequest)
                            do {
                                try context?.execute(userDeleteRequest)
                                try context?.save()
                            } catch {
                                print("error >>>>> ", error.localizedDescription)
                            }
                            self.chatModel = nil
                            self.messagesArray = []
                            self.chatTableView.reloadData()
                            // self.fetchData()
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            }
        }
    }
    
    // Block User
    func blockUser(block_action: String) {
        Async.background {
            BlockUsersManager.instance.blockUser(user_id: self.recipientID, block_action: block_action, completionBlock: { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            if success?.blockStatus == "blocked" {
                                self.view.makeToast("User has been blocked!!")
                            } else if success?.blockStatus == "un-blocked" {
                                self.view.makeToast(NSLocalizedString("User has been unblocked!!", comment: "User has been unblocked!!"))
                            } else {
                                self.view.makeToast(success?.blockStatus ?? "")
                            }
                            self.fetchReciverUserProfile()
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            })
        }
    }
    
    private func fetchReciverUserProfile() {
        let status = AppInstance.instance.getUserSession()
        if status {
            let sessionId = AppInstance.instance._sessionId
            Async.background {
                GetUserDataManager.instance.getUserData(user_id: self.recipientID, session_Token: sessionId, fetch_type: API.Params.user_data) { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.userData = success?.user_data
                            self.setData()
                            self.setUpUnBlockView(isBlocked: self.userData?.is_blocked ?? false)
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    } else {
                        Async.main {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            }
        } else {
            print(InterNetError)
        }
    }
    
    // React Message Api Call
    private func reactMessageApi(message_id: String, reaction: String, indexPath: IndexPath) {
        Async.background {
            ChatManager.instance.reactMessage(message_id: message_id, reaction: reaction, completionBlock: { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            print(success?.message ?? "")
                            if self.messagesArray[indexPath.row].reaction?.is_reacted == true {
                                self.messageArray[indexPath.row].reaction = ReactionModel(the1: nil, the2: nil, the3: nil, the4: nil, the5: nil, the6: nil, is_reacted: false, type: "", count: 0)
                                self.messagesArray[indexPath.row].reaction = Reactions(id: self.messagesArray[indexPath.row].message_id ?? "", reaction: self.messageArray[indexPath.row].reaction)
                            } else {
                                self.messageArray[indexPath.row].reaction = ReactionModel(the1: reaction == "1" ? 1 : nil, the2: reaction == "2" ? 1 : nil, the3: reaction == "3" ? 1 : nil, the4: reaction == "4" ? 1 : nil, the5: reaction == "5" ? 1 : nil, the6: reaction == "6" ? 1 : nil, is_reacted: true, type: reaction, count: 1)
                                self.messagesArray[indexPath.row].reaction = Reactions(id: self.messagesArray[indexPath.row].message_id ?? "", reaction: self.messageArray[indexPath.row].reaction)
                            }
                            self.chatTableView.reloadRows(at: [indexPath], with: .automatic)
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            })
        }
    }
    
    private func createAgoraCall(recipient_id: String, call_Type: String, user: UserData) {
        if Connectivity.isConnectedToNetwork() {
            Async.background {
                CallManager.instance.agoraCall(recipient_id: recipient_id, access_token: AppInstance.instance._sessionId, type: "create", call_Type: call_Type, completionBlock: { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.socketHelper.emit_user_notification(recipient_id: recipient_id)
                                switch call_Type {
                                case "audio":
                                    if let newVC = R.storyboard.call.agoraAudioCallVC() {
                                        newVC.outgoingCallData = success
                                        newVC.call_id = String(success?.id ?? 0)
                                        newVC.room_name = success?.room_name ?? ""
                                        newVC.userData = user
                                        self.navigationController?.pushViewController(newVC, animated: true)
                                    }
                                case "video":
                                    if let newVC = R.storyboard.call.agoraVideoCallVC() {
                                        newVC.outgoingCallData = success
                                        newVC.call_id = String(success?.id ?? 0)
                                        newVC.room_name = success?.room_name ?? ""
                                        newVC.userData = user
                                        self.navigationController?.pushViewController(newVC, animated: true)
                                    }
                                default:
                                    break
                                }
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(sessionError?.errors?.error_text)
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(serverError?.errors?.error_text)
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(error?.localizedDescription)
                            }
                        }
                    }
                })
            }
        } else {
            self.dismissProgressDialog {
                self.view.makeToast(InterNetError)
            }
        }
    }
    
    private func createTwilioCall(recipient_id: String, call_Type: String, user: UserData) {
        if Connectivity.isConnectedToNetwork() {
            Async.background {
                TwilloCallmanager.instance.twilioCall(recipient_id: recipient_id, access_token: AppInstance.instance._sessionId, type: "create", call_Type: call_Type, completionBlock: { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.socketHelper.emit_user_notification(recipient_id: recipient_id)
                                switch call_Type {
                                case "audio":
                                    if let newVC = R.storyboard.call.twilioAudioCallVC() {
                                        newVC.outgoingCallData = success
                                        newVC.call_id = String(success?.id ?? 0)
                                        newVC.room_name = success?.room_name ?? ""
                                        newVC.userData = user
                                        self.navigationController?.pushViewController(newVC, animated: true)
                                    }
                                case "video":
                                    if let newVC = R.storyboard.call.twilioVideoCallVC() {
                                        newVC.outgoingCallData = success
                                        newVC.call_id = String(success?.id ?? 0)
                                        newVC.room_name = success?.room_name ?? ""
                                        newVC.userData = user
                                        self.navigationController?.pushViewController(newVC, animated: true)
                                    }
                                default:
                                    break
                                }
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(sessionError?.errors?.error_text)
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(serverError?.errors?.error_text)
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(error?.localizedDescription)
                            }
                        }
                    }
                })
            }
        } else {
            self.dismissProgressDialog {
                self.view.makeToast(InterNetError)
            }
        }
    }
    
}

//MARK: TableView Delegate & DataSource Method's
extension ChatViewController: UITableViewDelegate, UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return messagesArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let objChatList = messagesArray[indexPath.row]
        guard let type = objChatList.type else { return UITableViewCell() }
        switch type {
        case "left_text":
            let lat = Double(objChatList.lat ?? "0.0") ?? 0.0
            let long = Double(objChatList.lng ?? "0.0") ?? 0.0
            if lat > 0.0 || long > 0.0 {
                let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftLocationTableViewCell.identifier, for: indexPath) as! LeftLocationTableViewCell
                self.setLeftLocationData(lat: lat, long: long, cell: cell, indexPathForCell: indexPath)
                return cell
            } else {
                let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftTextTableViewCell.identifier, for: indexPath) as! LeftTextTableViewCell
                self.setLeftTextData(cell: cell, indexPathForCell: indexPath)
                return cell
            }
        case "right_text":
            let lat = Double(objChatList.lat ?? "0.0") ?? 0.0
            let long = Double(objChatList.lng ?? "0.0") ?? 0.0
            if lat > 0.0 || long > 0.0 {
                let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightLocationTableViewCell.identifier, for: indexPath) as! RightLocationTableViewCell
                self.setRightLocationData(lat: lat, long: long, cell: cell, indexPathForCell: indexPath)
                return cell
            } else {
                let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightTextTableViewCell.identifier, for: indexPath) as! RightTextTableViewCell
                self.setRightTextData(cell: cell, indexPathForCell: indexPath)
                return cell
            }
        case "right_image":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightImageTableViewCell.identifier, for: indexPath) as! RightImageTableViewCell
            self.setRightImageData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_image":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftImageTableViewCell.identifier, for: indexPath) as! LeftImageTableViewCell
            self.setLeftImageData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_video":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftVideoTableViewCell.identifier, for: indexPath) as! LeftVideoTableViewCell
            self.setLeftVideoData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_video":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightVideoTableViewCell.identifier, for: indexPath) as! RightVideoTableViewCell
            self.setRightVideoData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_gif":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightGifTableViewCell.identifier, for: indexPath) as! RightGifTableViewCell
            self.setRightGifData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_gif":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftGifTableViewCell.identifier, for: indexPath) as! LeftGifTableViewCell
            self.setLeftGifData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_contact":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftContactTableViewCell.identifier, for: indexPath) as! LeftContactTableViewCell
            self.setLeftContactData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_contact":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightContactTableViewCell.identifier, for: indexPath) as! RightContactTableViewCell
            self.setRightContactData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_file":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftDocumentTableViewCell.identifier, for: indexPath) as! LeftDocumentTableViewCell
            self.setLeftDocumentData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_file":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightDocumentTableViewCell.identifier, for: indexPath) as! RightDocumentTableViewCell
            self.setRightDocumentData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_audio":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftAudioTableViewCell.identifier, for: indexPath) as! LeftAudioTableViewCell
            self.setLeftAudioData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_audio":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightAudioTableViewCell.identifier, for: indexPath) as! RightAudioTableViewCell
            self.setRightAudioData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_sticker":
            let cell = self.chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftStickerCell.identifier, for: indexPath) as! LeftStickerCell
            self.setLeftStickerData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_sticker":
            let cell = self.chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightStickerCell.identifier, for: indexPath) as! RightStickerCell
            self.setRightStickerData(cell: cell, indexPathForCell: indexPath)
            return cell
        default:
            return UITableViewCell()
        }
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
    
    // Set Left Text Data
    private func setLeftTextData(cell: LeftTextTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedLabel.text = objChatList.forward == "0" ? "" : "Forwarded"
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.userStackView.isHidden = true
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
            if isColor != "" {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyStoryTitleLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyStoryTitleLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            if isColor != "" {
                cell.replyBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyUserLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyMessageView.isHidden = true
            cell.replyUserLabel.text = ""
            cell.replyMessageLabel.text = ""
        }
        cell.hideAnimation()
        let messageString = self.decryptionAESModeECB(messageData: objChatList._text, key: objChatList._time) ?? ""
        cell.masageTextLabel.text = messageString
        cell.setUPLinkView(messageString: messageString, tableView: self.chatTableView)
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
    }
    
    // Set Right Text Data
    private func setRightTextData(cell: RightTextTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedLabel.text = objChatList.forward == "0" ? "" : "Forwarded"
        cell.forwardedView.isHidden = objChatList.forward == "0"
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
            cell.replyUserLabel.text = ""
            cell.replyMessageLabel.text = ""
        }
        cell.hideAnimation()
        let messageString = "\(self.decryptionAESModeECB(messageData: objChatList._text, key: objChatList._time) ?? objChatList._text)"
        cell.messaageTextLabel.text = "\(messageString)"
        cell.setUPLinkView(messageString: messageString, tableView: self.chatTableView)
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageVIew.isHidden = false
        } else {
            cell.starImageVIew.isHidden = true
        }
        if isColor != "" {
            cell.messageView.backgroundColor = UIColor(hex: isColor)
        } else {
            cell.messageView.backgroundColor = UIColor(hex: "#C83747")
        }
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        }
    }
    
    // Set Left Location Data
    private func setLeftLocationData(lat: Double, long: Double, cell: LeftLocationTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.userStackView.isHidden = true
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
            if isColor != "" {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyStoryTitleLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyStoryTitleLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            if isColor != "" {
                cell.replyBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyUserLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.configureMapView(lat: lat, long: long)
        cell.mapButton.tag = indexPathForCell.row
        cell.mapButton.addTarget(self, action: #selector(self.setLocationNavigaction), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
    }
    
    // Set Right Location Data
    private func setRightLocationData(lat: Double, long: Double, cell: RightLocationTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.configureMapView(lat: lat, long: long)
        cell.mapButton.tag = indexPathForCell.row
        cell.mapButton.addTarget(self, action: #selector(self.setLocationNavigaction), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        if isColor != "" {
            cell.messageView.backgroundColor = UIColor(hex: isColor)
        } else {
            cell.messageView.backgroundColor = UIColor(hex: "#C83747")
        }
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        }
    }
    
    // Set Left Image Data
    private func setLeftImageData(cell: LeftImageTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.userStackView.isHidden = true
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
            if isColor != "" {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyStoryTitleLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyStoryTitleLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            if isColor != "" {
                cell.replyBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyUserLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let imageUrl = URL(string: objChatList.media ?? "")
        cell.imageUrl = imageUrl
        if AppInstance.instance.isDownloadImage == false {
            if let imageURL = imageUrl, let localURL = MediaDownloader.shared.getCachedLocalURL(for: imageURL),
               FileManager.default.fileExists(atPath: localURL.path) {
                cell.loadImage(from: localURL)
                cell.blurView.isHidden = true // Hide download button
            } else {
                let indicator = SDWebImageActivityIndicator.medium
                cell.sendImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.sendImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
            }
        } else {
            cell.blurView.isHidden = true
            let indicator = SDWebImageActivityIndicator.medium
            cell.sendImageView.sd_imageIndicator = indicator
            DispatchQueue.global(qos: .userInteractive).async {
                cell.sendImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
            }
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.messageImageButton.tag = indexPathForCell.row
        cell.messageImageButton.addTarget(self, action: #selector(self.clickImageClick), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
    }
    
    // Set Right Image Data
    private func setRightImageData(cell: RightImageTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let imageUrl = URL(string: objChatList.media ?? "")
        cell.imageUrl = imageUrl
        if AppInstance.instance.isDownloadImage == false {
            if let imageURL = imageUrl, let localURL = MediaDownloader.shared.getCachedLocalURL(for: imageURL),
               FileManager.default.fileExists(atPath: localURL.path) {
                cell.loadImage(from: localURL)
                cell.blurView.isHidden = true // Hide download button
            } else {
                let indicator = SDWebImageActivityIndicator.medium
                cell.sendImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.sendImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
            }
        } else {
            cell.blurView.isHidden = true
            let indicator = SDWebImageActivityIndicator.medium
            cell.sendImageView.sd_imageIndicator = indicator
            DispatchQueue.global(qos: .userInteractive).async {
                cell.sendImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
            }
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.messageImageButton.tag = indexPathForCell.row
        cell.messageImageButton.addTarget(self, action: #selector(self.clickImageClick), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        if isColor != "" {
            cell.messageView.backgroundColor = UIColor(hex: isColor)
        } else {
            cell.messageView.backgroundColor = UIColor(hex: "C83747")
        }
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        }
    }
    
    // Set Left Video Data
    private func setLeftVideoData(cell: LeftVideoTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.userStackView.isHidden = true
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
            if isColor != "" {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyStoryTitleLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyStoryTitleLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            if isColor != "" {
                cell.replyBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyUserLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        let videoUrl = URL(string: objChatList.media ?? "")
        cell.videoUrl = videoUrl
        cell.videoImageView.image = UIImage(named: "")
        if AppInstance.instance.isDownloadVideo == false {
            if let videoUrl = videoUrl, let localURL = MediaDownloader.shared.getCachedLocalURL(for: videoUrl),
               FileManager.default.fileExists(atPath: localURL.path) {
                DispatchQueue.global(qos: .userInteractive).async {
                    AppInstance.instance.generateThumbnail(from: localURL, completion: { image in
                        DispatchQueue.main.async {
                            if let image = image {
                                cell.videoImageView.image = image
                            } else {
                                cell.videoImageView.image = UIImage(named: "")
                            }
                        }
                    })
                }
                cell.blurView.isHidden = true // Hide download button
            } else {
                DispatchQueue.global(qos: .userInteractive).async {
                    AppInstance.instance.generateThumbnail(from: videoUrl, completion: { image in
                        DispatchQueue.main.async {
                            if let image = image {
                                cell.videoImageView.image = image
                            } else {
                                cell.videoImageView.image = UIImage(named: "")
                            }
                        }
                    })
                }
            }
        } else {
            cell.blurView.isHidden = true
            DispatchQueue.global(qos: .userInteractive).async {
                AppInstance.instance.generateThumbnail(from: videoUrl, completion: { image in
                    DispatchQueue.main.async {
                        if let image = image {
                            cell.videoImageView.image = image
                        } else {
                            cell.videoImageView.image = UIImage(named: "")
                        }
                    }
                })
            }
        }
        cell.messageVideoButton.tag = indexPathForCell.row
        cell.messageVideoButton.addTarget(self, action: #selector(self.clickVideoButton), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
    }
    
    // Set Right Video Data
    private func setRightVideoData(cell: RightVideoTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                if (Double(objChatList.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let videoUrl = URL(string: objChatList.media ?? "")
        cell.videoUrl = videoUrl
        cell.videoImageView.image = UIImage(named: "")
        if AppInstance.instance.isDownloadVideo == false {
            if let videoUrl = videoUrl, let localURL = MediaDownloader.shared.getCachedLocalURL(for: videoUrl),
               FileManager.default.fileExists(atPath: localURL.path) {
                DispatchQueue.global(qos: .userInteractive).async {
                    AppInstance.instance.generateThumbnail(from: localURL, completion: { image in
                        DispatchQueue.main.async {
                            if let image = image {
                                cell.videoImageView.image = image
                            } else {
                                cell.videoImageView.image = UIImage(named: "")
                            }
                        }
                    })
                }
                cell.blurView.isHidden = true // Hide download button
            } else {
                DispatchQueue.global(qos: .userInteractive).async {
                    AppInstance.instance.generateThumbnail(from: videoUrl, completion: { image in
                        DispatchQueue.main.async {
                            if let image = image {
                                cell.videoImageView.image = image
                            } else {
                                cell.videoImageView.image = UIImage(named: "")
                            }
                        }
                    })
                }
            }
        } else {
            cell.blurView.isHidden = true
            DispatchQueue.global(qos: .userInteractive).async {
                AppInstance.instance.generateThumbnail(from: videoUrl, completion: { image in
                    DispatchQueue.main.async {
                        if let image = image {
                            cell.videoImageView.image = image
                        } else {
                            cell.videoImageView.image = UIImage(named: "")
                        }
                    }
                })
            }
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.messageVideoButton.tag = indexPathForCell.row
        cell.messageVideoButton.addTarget(self, action: #selector(self.clickVideoButton), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        if isColor != "" {
            cell.messageView.backgroundColor = UIColor(hex: isColor)
        } else {
            cell.messageView.backgroundColor = UIColor(hex: "C83747")
        }
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        }
    }
    
    // Set Left Gif Data
    private func setLeftGifData(cell: LeftGifTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.userStackView.isHidden = true
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
            if isColor != "" {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyStoryTitleLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyStoryTitleLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                if (Double(objChatList.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            if isColor != "" {
                cell.replyBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyUserLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        let gifUrl = URL(string: objChatList.stickers ?? "")
        let indicator = SDWebImageActivityIndicator.medium
        cell.videoImageView.sd_imageIndicator = indicator
        DispatchQueue.global(qos: .userInteractive).async {
            cell.videoImageView.sd_setImage(with: gifUrl, placeholderImage: UIImage(named: ""))
        }
        cell.messageGifButton.tag = indexPathForCell.row
        cell.messageGifButton.addTarget(self, action: #selector(self.clickGif), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
    }
    
    // Set Right Gif Data
    private func setRightGifData(cell: RightGifTableViewCell, indexPathForCell:IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                if (Double(objChatList.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        let gifUrl = URL(string: objChatList.stickers ?? "")
        let indicator = SDWebImageActivityIndicator.medium
        cell.videoImageView.sd_imageIndicator = indicator
        DispatchQueue.global(qos: .userInteractive).async {
            cell.videoImageView.sd_setImage(with: gifUrl, placeholderImage: UIImage(named: ""))
        }
        cell.messageGifButton.tag = indexPathForCell.row
        cell.messageGifButton.addTarget(self, action: #selector(self.clickGif), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        if isColor != "" {
            cell.messageView.backgroundColor = UIColor(hex: isColor)
        } else {
            cell.messageView.backgroundColor = UIColor(hex: "C83747")
        }
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        }
    }
    
    // Set Left Contact Data
    private func setLeftContactData(cell: LeftContactTableViewCell,  indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = self.messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.userStackView.isHidden = true
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
            if isColor != "" {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyStoryTitleLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyStoryTitleLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                if (Double(objChatList.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            if isColor != "" {
                cell.replyBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyUserLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let phoneData = self.decryptionAESModeECB(messageData: objChatList._text, key: objChatList._time) ?? ""
        let dict = htmlToString(text: phoneData)
        let contactName = ((dict?["Key"] as? String) ?? "")
        let phoneNumber = ((dict?["Value"] as? String) ?? "")
        if contactName != "" {
            cell.contactNameLabel.text = "\(contactName)"
        } else if phoneNumber != "" {
            cell.contactNameLabel.text = "\(phoneNumber)"
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.contactButton.tag = indexPathForCell.row
        cell.contactButton.addTarget(self, action: #selector(self.openContact), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        if isColor != "" {
            cell.contactImageView.tintColor = UIColor(hex: isColor)
        } else {
            cell.contactImageView.tintColor = UIColor(hex: "C83747")
        }
    }
    
    // Set Right Contact Data
    private func setRightContactData(cell: RightContactTableViewCell,  indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = self.messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                if (Double(objChatList.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let phoneData = self.decryptionAESModeECB(messageData: objChatList._text, key: objChatList._time) ?? ""
        let dict = htmlToString(text: phoneData)
        let contactName = ((dict?["Key"] as? String) ?? "")
        let phoneNumber = ((dict?["Value"] as? String) ?? "")
        if contactName != "" {
            cell.contactNameLabel.text = "\(contactName)"
        } else if phoneNumber != "" {
            cell.contactNameLabel.text = "\(phoneNumber)"
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.contactButton.tag = indexPathForCell.row
        cell.contactButton.addTarget(self, action: #selector(self.openContact), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        if isColor != "" {
            cell.messageView.backgroundColor = UIColor(hex: isColor)
        } else {
            cell.messageView.backgroundColor = UIColor(hex: "C83747")
        }
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        }
    }
    
    // Set Left Document Data
    private func setLeftDocumentData(cell: LeftDocumentTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.userStackView.isHidden = true
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
            if isColor != "" {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyStoryTitleLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyStoryTitleLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            if isColor != "" {
                cell.replyBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyUserLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let fileURL = URL(string: objChatList.media ?? "")
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.fileNameLabel.text = fileURL?.lastPathComponent ?? ""
        cell.fileSizeLabel.text = objChatList.file_size
        cell.fileMessageButton.tag = indexPathForCell.row
        cell.fileMessageButton.addTarget(self, action: #selector(self.clickFile), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        if isColor != "" {
            cell.fileButton.backgroundColor = UIColor(hex: isColor)
        } else {
            cell.fileButton.backgroundColor = UIColor(hex: "C83747")
        }
    }
    
    // Set Right Document Document
    private func setRightDocumentData(cell: RightDocumentTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let fileURL = URL(string: objChatList.media ?? "")
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.fileNameLabel.text = fileURL?.lastPathComponent ?? ""
        cell.fileSizeLabel.text = objChatList.file_size
        cell.fileMessageButton.tag = indexPathForCell.row
        cell.fileMessageButton.addTarget(self, action: #selector(self.clickFile), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        if isColor != "" {
            cell.messageView.backgroundColor = UIColor(hex: isColor)
            cell.fileImageView.tintColor = UIColor(hex: isColor)
        } else {
            cell.messageView.backgroundColor = UIColor(hex: "C83747")
            cell.fileImageView.tintColor = UIColor(hex: "C83747")
        }
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        }
    }
    
    // Set Left Audio Data
    private func setLeftAudioData(cell: LeftAudioTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.userStackView.isHidden = true
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
            if isColor != "" {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyStoryTitleLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyStoryTitleLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            if isColor != "" {
                cell.replyBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyUserLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        if let audioURL = URL(string: objChatList.media ?? "") {
            cell.playButtonTapHandler = {
                AudioPlayerHelper.shared.playAudio(at: indexPathForCell, url: audioURL)
            }
            cell.setupAudioPlayer(url: audioURL, indexPath: indexPathForCell)
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        if isColor != "" {
            cell.playButton.backgroundColor = UIColor(hex: isColor)
            cell.audioSliderView.minimumTrackTintColor = UIColor(hex: isColor)
            cell.audioSliderView.maximumTrackTintColor = UIColor(hex: isColor).withAlphaComponent(0.34)
        } else {
            cell.playButton.backgroundColor = UIColor(hex: "C83747")
            cell.audioSliderView.minimumTrackTintColor = UIColor(hex: "C83747")
            cell.audioSliderView.maximumTrackTintColor = UIColor(hex: "C83747").withAlphaComponent(0.34)
        }
    }
    
    // Set Right Audio Data
    private func setRightAudioData(cell: RightAudioTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        if let audioURL = URL(string: objChatList.media ?? "") {
            cell.playButtonTapHandler = {
                AudioPlayerHelper.shared.playAudio(at: indexPathForCell, url: audioURL)
            }
            cell.setupAudioPlayer(url: audioURL, indexPath: indexPathForCell)
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        if isColor != "" {
            cell.messageView.backgroundColor = UIColor(hex: isColor)
            cell.playButton.tintColor = UIColor(hex: isColor)
        } else {
            cell.messageView.backgroundColor = UIColor(hex: "C83747")
            cell.playButton.tintColor = UIColor(hex: "C83747")
        }
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        }
    }
    
    // Set Left Sticker Data
    private func setLeftStickerData(cell: LeftStickerCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.userStackView.isHidden = true
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
            if isColor != "" {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyStoryTitleLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyStoryBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyStoryTitleLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            if isColor != "" {
                cell.replyBorderView.backgroundColor = UIColor(hex: isColor)
                cell.replyUserLabel.textColor = UIColor(hex: isColor)
            } else {
                cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
                cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let stickerUrl = URL(string: objChatList.media ?? "")
        let indicator = SDWebImageActivityIndicator.medium
        cell.sendImageView.sd_imageIndicator = indicator
        DispatchQueue.global(qos: .userInteractive).async {
            cell.sendImageView.sd_setImage(with: stickerUrl, placeholderImage: UIImage(named: ""))
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
    }
    
    // Set Right Sticker Data
    private func setRightStickerData(cell: RightStickerCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        cell.isColor = self.isColor
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        if objChatList.story != nil {
            cell.replyStoryView.isHidden = false
            cell.replyStoryTitleLabel.text = "Story"
            if objChatList.story?.video == nil {
                let imageUrl = URL(string: objChatList.story?.thumbnail ?? "")
                let indicator = SDWebImageActivityIndicator.medium
                cell.replyStoryImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.replyStoryImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
                cell.replyStoryMessageLabel.text = "Image"
            } else {
                if let videoURL = URL(string: objChatList.story?.video?.filename ?? "") {
                    cell.replyStoryImageView.image = UIImage(named: "")
                    DispatchQueue.global(qos: .userInteractive).async {
                        self.generateThumbnail(from: videoURL, completion: { image in
                            DispatchQueue.main.async {
                                if let image = image {
                                    cell.replyStoryImageView.image = image
                                } else {
                                    cell.replyStoryImageView.image = UIImage(named: "")
                                }
                            }
                        })
                    }
                }
                cell.replyStoryMessageLabel.text = "Video"
            }
        } else {
            cell.replyStoryView.isHidden = true
            cell.replyStoryTitleLabel.text = ""
            cell.replyStoryMessageLabel.text = ""
        }
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = self.userData?.name
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let stickerUrl = URL(string: objChatList.media ?? "")
        let indicator = SDWebImageActivityIndicator.medium
        cell.sendImageView.sd_imageIndicator = indicator
        DispatchQueue.global(qos: .userInteractive).async {
            cell.sendImageView.sd_setImage(with: stickerUrl, placeholderImage: UIImage(named: ""))
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            if isColor != "" {
                cell.lastSeenImage.tintColor = UIColor(hex: isColor)
            } else {
                cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
            }
        }
    }
    
    /*override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {
     self.chatTableView.indexPathsForVisibleRows![0]
     chatTableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Top, animated: false)
     }*/
    
    func getFormattedDateFromUTC(RFC3339: String) -> String? {
        guard let date = getDateFromUTC(RFC3339: RFC3339),
              let timeZone = getTimeZoneFromUTC(RFC3339: RFC3339) else {
            return nil
        }
        let formatter = DateFormatter()
        formatter.dateFormat = "h:mma EEE, MMM d yyyy"
        formatter.amSymbol = "AM"
        formatter.pmSymbol = "PM"
        formatter.timeZone = timeZone // preserve local time zone
        return formatter.string(from: date)
    }
    
    func getDateFromUTC(RFC3339: String) -> Date? {
        let formatter = ISO8601DateFormatter()
        return formatter.date(from: RFC3339)
    }
    
    func getTimeZoneFromUTC(RFC3339: String) -> TimeZone? {
        switch RFC3339.suffix(6) {
        case "+05:30":
            return TimeZone(identifier: "Asia/Kolkata")
        case "+05:45":
            return TimeZone(identifier: "Asia/Kathmandu")
        default:
            return nil
        }
    }
    
    // Click Video Button
    @objc func clickVideoButton(_ sender: UIButton) {
        let object = self.messagesArray[sender.tag]
        let player = AVPlayer(url: URL(string: object.media ?? "")!)
        let vc = AVPlayerViewController()
        vc.player = player
        self.present(vc, animated: true) {
            vc.player?.play()
        }
    }
    
    // Click Image Click
    @objc func clickImageClick(_ sender: UIButton) {
        let object = self.messagesArray[sender.tag]
        let vc = R.storyboard.dashboard.showImageVC()
        vc?.imageURL = object.media ?? ""
        vc?.isGif = false
        vc?.modalPresentationStyle = .fullScreen
        vc?.modalTransitionStyle = .coverVertical
        self.present(vc!, animated: true, completion: nil)
    }
    
    // Click File
    @objc func clickFile(_ sender: UIButton) {
        let object = self.messagesArray[sender.tag]
        if let pdfURL = URL(string: object.media ?? "") {
            let safariViewController = SFSafariViewController(url: pdfURL)
            safariViewController.delegate = self
            present(safariViewController, animated: true, completion: nil)
        }
    }
    
    // Open Contact
    @objc func openContact(_ sender: UIButton) {
        let object = self.messagesArray[sender.tag]
        let phoneString = self.decryptionAESModeECB(messageData: object._text, key: object._time) ?? ""
        let phoneData = htmlToString(text: phoneString)
        let contact = CNMutableContact()
        contact.givenName = phoneData?["Key"] as? String ?? ""
        contact.phoneNumbers = [CNLabeledValue(label: CNLabelHome, value: CNPhoneNumber(stringValue: phoneData?["Value"] as? String ?? ""))]
        let contactViewController = CNContactViewController(forNewContact: contact)
        contactViewController.delegate = self
        let navigationController = UINavigationController(rootViewController: contactViewController)
        present(navigationController, animated: true, completion: nil)
    }
    
    @objc func setLocationNavigaction(_ sender: UIButton) {
        let object = self.messagesArray[sender.tag]
        guard let url = URL(string: "comgooglemaps://") else {
            return
        }
        if UIApplication.shared.canOpenURL(url) {
            let url = URL(string: "comgooglemaps://?saddr=&daddr=\(object.lng ?? ""),\(object.lng ?? "")&directionsmode=driving")
            UIApplication.shared.open(url!, options: [:], completionHandler: nil)
        } else {
            let regionDistance: CLLocationDistance = 10000
            let coordinates = CLLocationCoordinate2DMake(Double(object.lat ?? "") ?? 0, Double(object.lng ?? "") ?? 0)
            let regionSpan = MKCoordinateRegion(center: coordinates, latitudinalMeters: regionDistance, longitudinalMeters: regionDistance)
            var options = NSObject()
            options = [
                MKLaunchOptionsMapCenterKey: NSValue(mkCoordinate: regionSpan.center),
                MKLaunchOptionsMapSpanKey: NSValue(mkCoordinateSpan: regionSpan.span),
                MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving
            ] as NSObject
            let placemark = MKPlacemark(coordinate: coordinates, addressDictionary: nil)
            let mapItem = MKMapItem(placemark: placemark)
            mapItem.openInMaps(launchOptions: options as? [String: AnyObject])
        }
    }
    
    @objc func clickGif(_ sender: UIButton) {
        let object = self.messagesArray[sender.tag]
        let vc = R.storyboard.dashboard.showImageVC()
        vc?.imageURL = object.stickers ?? ""
        vc?.isGif = true
        vc?.modalPresentationStyle = .fullScreen
        vc?.modalTransitionStyle = .coverVertical
        self.present(vc!, animated: true, completion: nil)
    }
    
}

// MARK: AudioPlayerDelegate Methods
extension ChatViewController: AudioPlayerDelegate {
    
    func playbackStateChanged(at indexPath: IndexPath?) {
        if let indexPath = indexPath {
            self.chatTableView.reloadRows(at: [indexPath], with: .none)
        }
    }
    
}
    
// MARK: CNContactViewControllerDelegate Methods
extension ChatViewController: CNContactViewControllerDelegate {
    
    func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
        dismiss(animated: true, completion: nil)
        if contact != nil {
            print("Contact saved successfully!")
        } else {
            print("Contact creation cancelled or failed.")
        }
    }
    
}

// MARK: SwipeToReplyCellDelegate
extension ChatViewController: SwipeToReplyCellDelegate {
    
    func handleSwipeToReply(indexPath: IndexPath) {
        let message = self.messagesArray[indexPath.row]
        self.setUpReplyMessageView(message: message)
    }
    
}

// MARK: - RecordViewDelegate Methods
extension ChatViewController: RecordViewDelegate {
    
    func onStart() {
        print("onStart")
        self.view.endEditing(true)
        self.audioRecorderHelper.startRecording()
        self.socketHelper.emit_recording(recipient_id: self.recipientID, user_id: AppInstance.instance._sessionId)
        self.audioRecordView.isHidden = false
        self.audioRecordButton.isHidden = true
        self.mediaButton.isHidden = true
        self.sendView.isHidden = true
    }
    
    func onCancel() {
        print("onCancel")
        self.audioRecordView.isHidden = true
        self.audioRecordButton.isHidden = false
        self.mediaButton.isHidden = false
        self.sendView.isHidden = false
        self.isSendRecordAudio = false
        self.audioRecorderHelper.cancelRecording()
        self.socketHelper.emit_typing_done(recipient_id: self.recipientID, user_id: AppInstance.instance._sessionId)
    }
    
    func onFinished(duration: CGFloat) {
        print("onFinished \(duration)")
        self.audioRecordView.isHidden = true
        self.audioRecordButton.isHidden = false
        self.mediaButton.isHidden = false
        self.sendView.isHidden = false
        self.isSendRecordAudio = true
        self.showAudioRecordView()
        self.audioRecorderHelper.stopRecording()
        self.socketHelper.emit_typing_done(recipient_id: self.recipientID, user_id: AppInstance.instance._sessionId)
    }
    
    func showAudioRecordView() {
        self.audioRecordSendView.isHidden = false
        self.audioRecordSendViewHeight.constant = 78
        UIView.animate(withDuration: 0.5) {
            self.view.layoutIfNeeded()
        }
    }
    
    func hideAudioRecordView() {
        self.audioRecoderPlayer?.stop()
        self.audioRecodeTimer?.invalidate()
        self.audioRecodeTimer = nil
        self.audioRecordSliderView.value = 0
        self.audioRecordSendViewHeight.constant = 0
        UIView.animate(withDuration: 0.5, animations: {
            self.view.layoutIfNeeded()
        }) { _ in
            self.audioRecordSendView.isHidden = true
        }
    }
    
}

// MARK: MessageOptionDelegate Methods
extension ChatViewController: MessageOptionDelegate {
    
    func handleMessageOptionTap(index: Int, optionName: String, indexPath: IndexPath) {
        let object = self.messagesArray[indexPath.row]
        if index == 0 {
            let messageString = "\(self.decryptionAESModeECB(messageData: object._text, key: object._time) ?? object._text)"
            UIPasteboard.general.string = messageString
        } else if index == 1 {
            if let newVC = R.storyboard.favorite.messageInfoViewController() {
                newVC.object = object
                self.navigationController?.pushViewController(newVC, animated: true)
            }
        } else if index == 2 {
            self.deleteMessage(messageID: object.message_id ?? "", indexPath: indexPath.row)
        } else if index == 3 {
            self.setUpReplyMessageView(message: object)
        } else if index == 4 {
            if let newVC = R.storyboard.favorite.getFriendVC() {
                newVC.message = object
                newVC.userData = self.userData
                self.navigationController?.pushViewController(newVC, animated: true)
            }
        } else if index == 5 {
            if let chat_id = self.chatModel?.chat_id {
                if object.pin == "no" {
                    object.pin = "yes"
                    self.pinMessageApi(message_id: object._message_id, pin: "yes", chat_id: chat_id)
                } else {
                    object.pin = "no"
                    self.pinMessageApi(message_id: object._message_id, pin: "no", chat_id: chat_id)
                }
                object.save()
            }
            print("pin >>>>> ", object.pin ?? "")
        } else if index == 6 {
            if let chat_id = self.chatModel?.chat_id {
                if object.fav == "no" {
                    object.fav = "yes"
                    self.favMessageApi(message_id: object._message_id, fav: "yes", chat_id: chat_id)
                } else {
                    object.fav = "no"
                    self.favMessageApi(message_id: object._message_id, fav: "no", chat_id: chat_id)
                }
                object.save()
            }
            print("fav >>>>> ", object.fav ?? "")
        }
    }
    
    func handleReactionTap(reaction: Int, optionName: String, indexPath: IndexPath) {
        let object = self.messagesArray[indexPath.row]
        let reaction = String(reaction)
        self.socketHelper.emit_register_reaction(id: object._message_id, reaction: reaction, user_id: AppInstance.instance._sessionId)
        // self.reactMessageApi(message_id: object._message_id, reaction: String(reaction), indexPath: indexPath)
    }
    
}

// MARK: UIViewControllerTransitioningDelegate Methods
extension ChatViewController: UIViewControllerTransitioningDelegate {
    
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        BottomSheetPresentationController(presentedViewController: presented, presenting: presenting)
    }
    
}

// MARK: MoreOptionDelegate Methods
extension ChatViewController: MoreOptionDelegate {
    
    func handleMoreOptionTap(optionName: String, index: Int) {
        switch index {
        case 0:
            if let newVC = R.storyboard.dashboard.userProfileViewController() {
                newVC.user_id = self.userData?.user_id ?? ""
                newVC.user_data = self.userData
                newVC.messageArray = self.messagesArray
                self.navigationController?.pushViewController(newVC, animated: true)
            }
        case 1:
            if self.userData?.is_blocked ?? false {
                self.blockUser(block_action: "un-block")
            } else {
                if let alertVC = R.storyboard.popup.warningAlertVC() {
                    alertVC.delegate = self
                    alertVC.titleText  = "Clear Chat"
                    alertVC.messageText = "Are you sure you want to delete messages?"
                    alertVC.okText = "YES"
                    alertVC.cancelText = "NO"
                    self.present(alertVC, animated: true, completion: nil)
                }
                self.blockUser(block_action: "block")
            }
        case 2:
            let ChangeColorVC = self.storyboard?.instantiateViewController(withIdentifier: "ChangeThemeColorViewController") as! ChangeThemeColorViewController
            ChangeColorVC.modalPresentationStyle = .custom
            ChangeColorVC.transitioningDelegate = self
            ChangeColorVC.delagete = self
            self.present(ChangeColorVC, animated: true)
        case 3:
            if let newVC = R.storyboard.settings.wallpaperViewController() {
                self.navigationController?.pushViewController(newVC, animated: true)
            }
        case 4:
            if let alertVC = R.storyboard.popup.warningAlertVC() {
                alertVC.delegate = self
                alertVC.titleText  = "Clear Chat"
                alertVC.messageText = "Are you sure you want to delete messages?"
                alertVC.okText = "YES"
                alertVC.cancelText = "NO"
                self.present(alertVC, animated: true, completion: nil)
            }
        case 5:
            if let newVC = R.storyboard.chat.pinnedAndFavouriteMessageVC() {
                newVC.headerTitle = "Favourited Messages"
                newVC.chatModel = self.chatModel
                newVC.isPinnedMessages = false
                newVC.messagesArray = self.favMessageArray
                self.navigationController?.pushViewController(newVC, animated: true)
            }
        case 6:
            if let newVC = R.storyboard.dashboard.mediaViewController() {
                newVC.messageArray = self.messagesArray
                newVC.user_id = userData?.user_id ?? ""
                self.navigationController?.pushViewController(newVC, animated: true)
            }
        case 7:
            if let newVC = R.storyboard.chat.userChatSearchConversationVC() {
                newVC.chatModel = self.chatModel
                newVC.userData = self.userData
                self.navigationController?.pushViewController(newVC, animated: true)
            }
        default:
            break
        }
    }
    
}

// MARK: WarningAlertVCDelegate Methods
extension ChatViewController: WarningAlertVCDelegate {
    
    func chatAlertOKButtonPressed(_ sender: UIButton) {
        self.deleteChat(user_id: self.recipientID)
    }
}

// MARK: ChatMediaOptionVCDelegate Methods
extension ChatViewController: ChatMediaOptionVCDelegate {
    
    func handleCameraButtonTap() {
        self.view.endEditing(true)
        if UIImagePickerController.isSourceTypeAvailable(.camera) {
            self.imagePicker.delegate = self
            self.imagePicker.sourceType = .camera
            self.imagePicker.mediaTypes = ["public.movie", "public.image"]
            self.imagePicker.allowsEditing = false
            self.present(self.imagePicker, animated: true, completion: nil)
        } else {
            if let messageAlertVC = R.storyboard.popup.messageAlertVC() {
                messageAlertVC.messageText = "You don't have camera"
                self.present(messageAlertVC, animated: true, completion: nil)
                messageAlertVC.confirmButton.isHidden = true
            }
        }
    }
    
    func handleImageAndVideoButtonTap() {
        self.view.endEditing(true)
        self.imagePicker.delegate = self
        self.imagePicker.sourceType = .photoLibrary
        self.imagePicker.mediaTypes = ["public.movie", "public.image"]
        self.imagePicker.allowsEditing = false
        self.present(self.imagePicker, animated: true, completion: nil)
    }
    
    func handleDocumentButtonTap() {
        self.view.endEditing(true)
        let contentTypes: [UTType] = [
            .init(filenameExtension: "doc")!,
            .init(filenameExtension: "docx")!,
            .pdf,
            .presentation,
            .spreadsheet,
            .plainText,
            .text
        ]
        let pickerController = UIDocumentPickerViewController(forOpeningContentTypes: contentTypes, asCopy: true)
        pickerController.title = "Document"
        pickerController.delegate = self
        pickerController.allowsMultipleSelection = false
        self.present(pickerController, animated: true, completion: nil)
    }
    
    func handleContactButtonTap() {
        self.view.endEditing(true)
        let contactPicker = CNContactPickerViewController()
        contactPicker.delegate = self
        contactPicker.displayedPropertyKeys = [CNContactPhoneNumbersKey]
        self.present(contactPicker, animated: true, completion: nil)
    }
    
    func handleGifButtonTap() {
        self.view.endEditing(true)
        if let newVC = R.storyboard.chat.gifVC() {
            newVC.delegate = self
            self.navigationController?.pushViewController(newVC, animated: true)
        }
    }
    
    func handleStickerButtonTap() {
        self.view.endEditing(true)
        let storeVC = SPUISearchViewController()
        storeVC.setUser(SPUser(userID: AppInstance.instance._userId))
        storeVC.delegate = self
        self.present(storeVC, animated: true)
    }
    
    func handleMusicButtonTap() {
        self.view.endEditing(true)
        let contentTypes: [UTType] = [
            .audio
        ]
        let pickerController = UIDocumentPickerViewController(forOpeningContentTypes: contentTypes, asCopy: true)
        pickerController.title = "Audio"
        pickerController.delegate = self
        pickerController.allowsMultipleSelection = false
        self.present(pickerController, animated: true, completion: nil)
    }
    
    func handleLocationButtonTap() {
        self.view.endEditing(true)
        let vc = R.storyboard.chat.locationVC()
        vc?.delegate = self
        self.navigationController?.pushViewController(vc!, animated: true)
    }
    
}

// MARK: UIImagePickerControllerDelegate & UINavigationControllerDelegate Methods
extension ChatViewController: UIImagePickerControllerDelegate & UINavigationControllerDelegate {
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true) {
            if let image = info[.originalImage] as? UIImage {
                if let newVC = R.storyboard.photoEditor.photoEditorVC() {
                    newVC.selectedImage = image
                    newVC.delegate = self
                    self.navigationController?.pushViewController(newVC, animated: true)
                }
            }
            if let videoURL = info[.mediaURL] as? URL {
                if let newVC = R.storyboard.story.videoEditorVC() {
                    newVC.delegate = self
                    newVC.videoUrl = videoURL
                    self.navigationController?.pushViewController(newVC, animated: true)
                }
            }
        }
    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true, completion: nil)
    }
    
}

// MARK: PhotoEditorVCDelegate
extension ChatViewController: PhotoEditorVCDelegate {
    
    func handlePhotoEditorSaveButtonTap(image: UIImage) {
        let imageData = image.jpegData(compressionQuality: 1)
        self.sendSelectedData(audioData: nil, imageData: imageData, videoData: nil, imageMimeType: imageData?.mimeType, VideoMimeType: nil, audioMimeType: nil, Type: "image", fileData: nil, fileExtension: nil, FileMimeType: nil)
    }
    
}

// MARK: VideoEditorVCDelegate
extension ChatViewController: VideoEditorVCDelegate {
    
    func videoEditorDidSaveVideo(url: URL) {
        let videoData = try? Data(contentsOf: url)
        self.sendSelectedData(audioData: nil, imageData: nil, videoData: videoData, imageMimeType: nil, VideoMimeType: videoData?.mimeType, audioMimeType: nil, Type: "video", fileData: nil, fileExtension: nil, FileMimeType: nil)
    }
    
}

// MARK: UIDocumentPickerDelegate Methods
extension ChatViewController: UIDocumentPickerDelegate {
    
    func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
        controller.dismiss(animated: true)
        let fileData = try? Data(contentsOf: url)
        let fileExtension = String(url.lastPathComponent.split(separator: ".").last!)
        switch controller.title {
        case "Document":
            self.sendSelectedData(audioData: nil, imageData: nil, videoData: nil, imageMimeType: nil, VideoMimeType: nil, audioMimeType: nil, Type: "file", fileData: fileData, fileExtension: fileExtension, FileMimeType: fileData?.mimeType)
        case "Audio":
            self.sendSelectedData(audioData: fileData, imageData: nil, videoData: nil, imageMimeType: nil, VideoMimeType: nil, audioMimeType: "application/octet-stream", Type: "audio", fileData: nil, fileExtension: nil, FileMimeType: nil)
        default:
            break
        }
    }
    
    func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
        print("Cancelled")
    }
    
}

// MARK: SFSafariViewControllerDelegate Methods
extension ChatViewController: SFSafariViewControllerDelegate {
    
    func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
        controller.dismiss(animated: true, completion: nil)
    }
    
}


// MARK: UITextViewDelegate Methods
extension ChatViewController: UITextViewDelegate {
    
    func textViewDidChange(_ textView: UITextView) {
        self.setSendButton()
    }
    
    func textViewDidEndEditing(_ textView: UITextView) {
        self.messageTextView.isEmojiKeyboard = false
    }
    
}

// MARK:  Api call on send Media Controller
extension ChatViewController {
    
    private func sendSelectedData(audioData: Data?, imageData: Data?, videoData: Data?, imageMimeType: String?, VideoMimeType: String?, audioMimeType: String?, Type: String?, fileData: Data?, fileExtension: String?, FileMimeType: String?) {
        let replyID = self.replyMessageID
        let messageHashId = Int(arc4random_uniform(UInt32(100000)))
        let sessionId = AppInstance.instance._sessionId
        let dataType = Type ?? ""
        if dataType == "image" {
            Async.background {
                ChatManager.instance.sendChatData(message_hash_id: messageHashId, receipent_id: self.recipientID, session_Token: sessionId, type: dataType, audio_data: nil, image_data: imageData, video_data: nil, imageMimeType: imageMimeType, videoMimeType: nil, audioMimeType: nil, text: "", file_data: nil, file_Extension: nil, fileMimeType: nil, reply_id: replyID, story_id: "") { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.resignFirstResponder()
                                if self.isReplyStatus {
                                    self.hideReplyMessageView()
                                }
                                self.fetchData()
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(sessionError?.errors?.error_text)
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(serverError?.errors?.error_text)
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(error?.localizedDescription)
                            }
                        }
                    }
                }
            }
        }
        if dataType == "audio" {
            Async.background {
                ChatManager.instance.sendChatData(message_hash_id: messageHashId, receipent_id: self.recipientID, session_Token: sessionId, type: dataType, audio_data: audioData, image_data: nil, video_data: nil, imageMimeType: nil, videoMimeType: nil, audioMimeType: audioMimeType, text: "", file_data: nil, file_Extension: "mp3", fileMimeType: nil, reply_id: replyID, story_id: "") { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.resignFirstResponder()
                                if self.isReplyStatus {
                                    self.hideReplyMessageView()
                                }
                                self.fetchData()
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(sessionError?.errors?.error_text)
                                print("sessionError = \(sessionError?.errors?.error_text ?? "")")
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(serverError?.errors?.error_text)
                                print("serverError = \(serverError?.errors?.error_text ?? "")")
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(error?.localizedDescription)
                                print("error = \(error?.localizedDescription ?? "")")
                            }
                        }
                    }
                }
            }
        }
        if dataType == "video" {
            Async.background {
                ChatManager.instance.sendChatData(message_hash_id: messageHashId, receipent_id: self.recipientID, session_Token: sessionId, type: dataType, audio_data: nil, image_data: nil, video_data: videoData, imageMimeType: nil, videoMimeType: VideoMimeType, audioMimeType: nil, text: "", file_data: nil, file_Extension: nil, fileMimeType: nil, reply_id: replyID, story_id: "") { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.resignFirstResponder()
                                if self.isReplyStatus {
                                    self.hideReplyMessageView()
                                }
                                self.fetchData()
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(sessionError?.errors?.error_text)
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(serverError?.errors?.error_text)
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(error?.localizedDescription)
                            }
                        }
                    }
                }
            }
        }
        if dataType == "file" {
            Async.background {
                ChatManager.instance.sendChatData(message_hash_id: messageHashId, receipent_id: self.recipientID, session_Token: sessionId, type: dataType, audio_data: nil, image_data: nil, video_data: nil, imageMimeType: nil, videoMimeType: nil, audioMimeType: nil, text: "", file_data: fileData, file_Extension: fileExtension, fileMimeType: FileMimeType, reply_id: replyID, story_id: "") { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.resignFirstResponder()
                                if self.isReplyStatus {
                                    self.hideReplyMessageView()
                                }
                                self.fetchData()
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(sessionError?.errors?.error_text)
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(serverError?.errors?.error_text)
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(error?.localizedDescription)
                            }
                        }
                    }
                }
            }
        }
    }
}

// MARK: DID SELECT GIF
extension  ChatViewController: didSelectGIFDelegate {
    
    func didSelectGIF(GIFUrl: String, id: String) {
        self.sendGIF(url: GIFUrl)
    }
    
    private func sendGIF(url: String) {
        let replyID = self.replyMessageID
        let messageHashId = Int(arc4random_uniform(UInt32(100000)))
        let recipientId = self.recipientID
        let sessionID = AppInstance.instance._sessionId
        Async.background {
            ChatManager.instance.sendGIF(message_hash_id: messageHashId, receipent_id: recipientId, URl: url , session_Token: sessionID, reply_id: replyID, story_id: "") { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.resignFirstResponder()
                            if self.isReplyStatus {
                                self.hideReplyMessageView()
                            }
                            self.fetchData()
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            }
        }
    }
    
    private func playSendMessageSound() {
        guard let url = Bundle.main.url(forResource: "Popup_SendMesseges", withExtension: "mp3") else { return }
        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
            try AVAudioSession.sharedInstance().setActive(true)
            self.sendMessageAudioPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
            self.sendMessageAudioPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
            guard let aPlayer = sendMessageAudioPlayer else { return }
            aPlayer.play()
            
        } catch let error {
            print(error.localizedDescription)
        }
    }
    
}

// MARK: SPUIDelegate Methods
extension ChatViewController: SPUIDelegate {
    
    func onStickerSingleTapped(_ view: SPUIView, sticker: SPSticker) {
        self.sendSticker(url: sticker.stickerImg, sticker_id: sticker.stickerId)
        self.view.endEditing(true)
    }
    
    private func sendSticker(url: String, sticker_id: Int) {
        let replyID = self.replyMessageID
        let messageHashId = Int(arc4random_uniform(UInt32(100000)))
        let recipientId = self.recipientID
        let sessionID = AppInstance.instance._sessionId
        Async.background {
            ChatManager.instance.sendSticker(message_hash_id: messageHashId, receipent_id: recipientId, sticker_id: sticker_id, URl: url, session_Token: sessionID, reply_id: replyID) { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.resignFirstResponder()
                            if self.isReplyStatus {
                                self.hideReplyMessageView()
                            }
                            self.fetchData()
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            }
        }
    }
    
}

// MARK: CNContactPickerDelegate Methods
extension ChatViewController: CNContactPickerDelegate {
    
    func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
        if let phoneNumber = contactProperty.value as? CNPhoneNumber {
            let contactNumber = phoneNumber.stringValue
            let fullName = CNContactFormatter.string(from: contactProperty.contact, style: .fullName)
            let extendedParam = ["Key": fullName, "Value": contactNumber] as? [String: String]
            if let theJSONData = try?  JSONSerialization.data(withJSONObject: extendedParam ?? [:], options: []) {
                let theJSONText = String(data: theJSONData, encoding: String.Encoding.utf8)
                print("JSON string = \(theJSONText ?? "")")
                self.sendContact(jsonPayload: theJSONText)
            }
        }
    }
    
    func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
        // Handle the cancel action
    }
    
    private func sendContact(jsonPayload: String?) {
        let replyID = self.replyMessageID
        let messageHashId = Int(arc4random_uniform(UInt32(100000)))
        ChatManager.instance.sendContactApiCall(message_hash_id: messageHashId, receipent_id: self.recipientID, sendType: "send", jsonPayload: jsonPayload ?? "", session_Token: AppInstance.instance.sessionId ?? "", reply_id: replyID, story_id: "") { (success, sessionError, serverError, error) in
            if success != nil {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.resignFirstResponder()
                        if self.isReplyStatus {
                            self.hideReplyMessageView()
                        }
                        self.fetchData()
                    }
                }
            } else if sessionError != nil {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.makeToast(sessionError?.errors?.error_text)
                    }
                }
            } else if serverError != nil {
                Async.main {
                    self.dismissProgressDialog {
                        let indexPath = NSIndexPath(item: ((self.messagesArray.count) - 1), section: 0)
                        self.chatTableView.scrollToRow(at: indexPath as IndexPath, at: UITableView.ScrollPosition.bottom, animated: true)
                        //self.view.makeToast(serverError?.errors?.errorText)
                    }
                }
            } else {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.makeToast(error?.localizedDescription)
                    }
                }
            }
        }
    }
    
}

// MARK: SEND LOCATION PROTOCOL
extension ChatViewController: sendLocationProtocol {
    
    func sendLocation(lat: Double, long: Double) {
        self.sendMessage(text: "", lat: lat, lng: long)
    }
    
    func sendMessage(text: String, lat: Double, lng: Double) {
        let replyID = self.replyMessageID
        let sessionToken = AppInstance.instance._sessionId
        ChatManager.instance.sendMessage(message: text, session_token: sessionToken, ReceipientId: self.recipientID, lat: lat, lng: lng, reply_id: replyID, story_id: "") { Success, AuthError, ServerKeyError, error in
            if Success != nil {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.resignFirstResponder()
                        if self.toneStatus {
                            self.playSendMessageSound()
                        } else {
                            
                        }
                        self.messageTextView.text = ""
                        self.setSendButton()
                        if self.isReplyStatus {
                            self.hideReplyMessageView()
                        }
                        self.fetchData()
                    }
                }
            } else if AuthError != nil {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.makeToast(AuthError?.errors?.error_text)
                    }
                }
            } else if ServerKeyError != nil {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.makeToast(ServerKeyError?.errors?.error_text)
                    }
                }
            } else {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.makeToast(error?.localizedDescription)
                    }
                }
            }
        }
    }
    
}

//MARK: UIDocumentInteractionController Delegate Method's
extension ChatViewController: UIDocumentInteractionControllerDelegate {
    
    func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
        return self
    }
    
    func documentInteractionControllerViewForPreview(_ controller: UIDocumentInteractionController) -> UIView? {
        return self.view
    }
    
}

//MARK: AudioRecorderHelperDelegate Methods
extension ChatViewController: AudioRecorderHelperDelegate {
    
    func audioRecordingFinished(success: Bool, audioURL: URL?) {
        self.audioFileURL = audioURL
        if let audioFileURL = self.audioFileURL {
            do {
                self.audioRecoderPlayer = try AVAudioPlayer(contentsOf: audioFileURL)
                self.audioRecoderPlayer.delegate = self
                self.audioRecoderPlayer.prepareToPlay()
                self.audioRecordSliderView.value = 0
                self.audioRecordSliderView.minimumValue = 0
                self.audioRecordSliderView.maximumValue = Float(self.audioRecoderPlayer?.duration ?? 0)
            } catch {
                print("Error initializing audio player: \(error)")
            }
        }
    }
    
}

// MARK: AVAudioPlayerDelegate Methods
extension ChatViewController: AVAudioPlayerDelegate {
    
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        self.audioRecoderPlayer?.pause()
        self.audioRecodeTimer?.invalidate()
        self.audioRecordSliderView.value = Float(self.audioRecoderPlayer.currentTime)
        self.audioRecordPlayButton.setImage(UIImage(named: "icon_play_vector"), for: .normal)
    }
    
}

// MARK: ChangeThemeColorDelegate Methods
extension ChatViewController: ChangeThemeColorDelegate {
    
    func handleChangeThemeColor(hex: String) {
        UserDefaults.standard.setChatColorHex(value: hex, ForKey: "ColorTheme")
        let objColor = UserDefaults.standard.value(forKey: "ColorTheme")
        self.isColor = objColor as? String ?? ""
        self.viewWillAppear(true)
        if isColor != "" {
            self.backButton.tintColor = UIColor(hex: isColor)
            self.audioCallButton.tintColor = UIColor(hex: isColor)
            self.videoCallButton.tintColor = UIColor(hex: isColor)
            self.moreButton.tintColor = UIColor(hex: isColor)
            self.mediaButton.backgroundColor = UIColor(hex: isColor)
            self.pinSideView.backgroundColor = UIColor(hex: isColor)
            self.pinMessageLabel.textColor = UIColor(hex: isColor)
            self.sendButton.tintColor = UIColor(hex: isColor)
            self.userProfileImageView.borderColorV = UIColor(hex: isColor)
            self.userProfileImageView.borderWidthV = 1
        }
        self.chatTableView.reloadData()
    }
    
}

class EmojiTextView: UITextView {
    
    var isEmojiKeyboard = false
    
    // required for iOS 13
    override var textInputContextIdentifier: String? { "" }
    
    override var textInputMode: UITextInputMode? {
        if self.isEmojiKeyboard {
            for mode in UITextInputMode.activeInputModes {
                if mode.primaryLanguage == "emoji" {
                    return mode
                }
            }
        } else {
            return UITextInputMode.activeInputModes.first
        }
        return nil
    }
    
}
