//
//  SessionUtil.swift
//  LegendTeam
//
//  Created by 梁博 on 20/12/21.
//

import Foundation
import NIMSDK
class SessionUtil {
    
    var topViewHeight: CGFloat = 0
    let mssagePageSize = 50
    //var session: NIMSession!
    //var conversation: V2NIMConversation!
    var conversationId : String!
    
    let showTimeInterval: TimeInterval = 180
    
    var cellModels: [SessionBaseModel]! = [SessionBaseModel]()
    /// Key: messageClientId。 ⚠️不能用messageServerId，因为消息可能是在发送中,导致没有messageServerId
    var msgIdDict: [String: SessionBaseModel]! = [String: SessionBaseModel]()
    
    func getLastMessageModel() -> SessionBaseModel? {
        var lastModel: SessionBaseModel?
        for model in cellModels {
            if let messageServerId = model.v2msg?.messageServerId, messageServerId.count > 0{
                lastModel = model
            }
        }
        return lastModel
    }
}

// private
extension SessionUtil {
    /// 最晚的时间， 也是排在最前面的时间
    func firtTimeStamp() -> TimeInterval {
        guard let model = cellModels.first else {
            return 0
        }
        return model.timeStamp
    }
    
    /// 最后一条消息的时候，也是离现在最近的时间
    func lastTimeInterval() -> TimeInterval {
        return cellModels.last?.timeStamp ?? 0
    }
    
    /// 是否能追加时间显示
    func shouldAppendTimestamp(model: SessionBaseModel) -> Bool {
        if model.cellType == .aiLoading{
            return false
        }
        return model.timeStamp - lastTimeInterval() > showTimeInterval
    }
    
    /// 是否能插入时间显示
    func shouldInsertTimestamp(model: SessionBaseModel) -> Bool {
        return firtTimeStamp() - model.timeStamp > showTimeInterval
    }
    
    /// 是否需要忽略本条消息，不创建model，不显示
    func ignore(info: IMBaseRemoteInfo) -> Bool{
        var ignore = false
        if let customAttachment = info.customAttachment{
            if let type = customAttachment.type{
                if type == .HEARTBEAT_LEVEL_DOWN ||
                    type == .HEARTBEAT_LEVEL_UP ||
                    type == .INSUFFICIENT_BALANCE ||
                    type == .VOICE_CHAT_CONTENT
                {
                    ignore = true
                }
            }else{
                // 没有type的自定义消息
                ignore = true
            }
        }
        
        return ignore
    }
    
    /// 是否需要追加一个model显示，判断一条消息显示两个model的情况
    func needDeriveModel(message: V2NIMMessage) -> Bool {
        if message.messageType == .MESSAGE_TYPE_CUSTOM{
            if let attachment = message.attachment?.raw, attachment.count > 0 {
                let model = CodableHelper.decode(IMCustomAttachment.self, from: attachment)
                if let type = model?.type, type.rawValue.uppercased() == CLCustomAttchType.IMAGE.rawValue{
                    return true
                }
            }
            
        }
        
        if message.serverExtension == nil {
            return false
        }
        let info = IMRemoteUtil.dealRemoteInfo(message: message)
        if info.cellType == .keyword
            || info.cellType == .gift
        {
            return true
        }
        return false
    }
    
    func needDecriveModel(with: IMBaseRemoteInfo) -> Bool{
        if let customAttachment = with.customAttachment, let type = customAttachment.type{
            if type == .IMAGE{
                return true
            }
        }
        
        if with.cellType == .keyword || with.cellType == .gift{
            return true
        }
        return false
    }
    
    /// 将model存在字典中
    func setIdIdctObject(model: SessionBaseModel) {
        if model.isDeriveModel {
            return
        }

        guard let messageID = model.v2msg?.messageClientId else { return }
        msgIdDict[messageID] = model
    }
    
    /// message是否已经存在model
    func modelIsExist(model: SessionBaseModel) -> Bool {
        guard let messageID = model.v2msg?.messageClientId else { return false }
        return msgIdDict[messageID] != nil
    }
    
    func logAllCellModels(){
        if APIConfig.environment == .test{
            var string = "☁️cellModels(\(cellModels.count):\n"
            for per in cellModels {
                string += "\(per)\n"
            }
            dlog(string)
        }
    }
}

// MARK: - Deal Models
/// Deal Models
extension SessionUtil {
    /// 根据类型创建cellModel
    func createCellModelWith(type: SessionCellType) -> SessionBaseModel {
        let model = SessionBaseModel()
        let configType = SessionBaseModel.getContentConfigClass(type: type)
        // 创建配置类
        model.config = configType.init()
        model.cellType = type
        
        switch type {
        case .image:
            model.shouldShowBubble = false
        case .gift:
            // 卡片
            model.shouldShowBubble = false
            model.shouldShowCardView = true
        case .timeStamp,.tips, .create, .keyword, .phonecall:
            model.shouldShowBubble = false
            model.shouldShowTips = true
        default:
            // 默认bubble
            model.shouldShowBubble = true
            model.shouldShowTips = false
            break
        }
        return model
    }
    
    func createCellModelWithCustom(attachment:String?) -> SessionBaseModel{
        let model = SessionBaseModel()
        
        guard let raw = attachment, let data = CodableHelper.decode(IMCustomAttachment.self, from: raw) else{
            return model
        }
        
//        switch data.type{
//        case .IMAGE: break
//            
//        }
        
        //let configType = SessionBaseModel.getContentConfigClass(type: type)
        
        
        return model
    }

    /// 处理查询回来的消息
    func dealMessages(messages: [V2NIMMessage]?, completion: @escaping ((_ messageDatas: [V2NIMMessage]?, _ error: Error?) -> Void)) {
        var tempModels = modelWithV2(datas: messages!)
        var tempMessages = messages ?? [V2NIMMessage]()
        
//        while tempModels.count < mssagePageSize, messages!.count > 0 {
//            tempMessages = NIMSDK.shared().conversationManager.messages(in: session, message: tempMessages.first, limit: mssagePageSize)!
//            if Array.realEmpty(array: tempMessages) {
//                break
//            }
//            let theModels = modelWith(messsages: tempMessages)
//            tempModels.insert(contentsOf: theModels, at: 0)
//        }
        
        
//        let indexs = insertMessagesWith(models: tempModels.reversed())
        DispatchQueue.main.async {
            completion( messages, nil)
        }
    }
    
    @discardableResult
    func inserMessageWith(message: V2NIMMessage, atIndex: Int) -> [Int]{
        let models = modelWithV2(datas: [message])
        guard let model = models.first else { return [] }
        self.cellModels.insert(model, at: atIndex)
        return [atIndex]
    }
    
    /// 追加model到数据源
    func appendWith(models: [SessionBaseModel]) -> [Int] {
        if Array.realEmpty(array: models) {
            return []
        }
        
        let count = cellModels.count
        for model in models {
            if modelIsExist(model: model), !model.isDeriveModel {
                continue
            }
            _ = appendWith(model: model)
        }
        
        var indexs = [Int]()
        for i in count ..< cellModels.count {
            indexs.append(i)
        }
        return indexs
    }


    /// 追加model到数据源
    @discardableResult
    func appendWith(model: SessionBaseModel) -> [Int] {
        var indexs = [Int]()
        if shouldAppendTimestamp(model: model) {
            addTimestamp(model: model, index: cellModels.count)
            indexs.append(cellModels.count)
        }
        
        cellModels.insert(model, at: cellModels.count)
        indexs.append(cellModels.count)
        setIdIdctObject(model: model)
        
        return indexs
    }

    /// 追加model到数据源
    func addTimestamp(model: SessionBaseModel, index: Int) {
        let timeModel = createCellModelWith(type: .timeStamp)
        timeModel.shouldShowBubble = false
        timeModel.shouldShowTips = true
        timeModel.timeStamp = model.v2msg?.createTime ?? model.timeStamp
        cellModels.insert(timeModel, at: index)
    }
    
    /// 通过消息查找当前model
    func findCellModel(message: V2NIMMessage?) -> SessionBaseModel? {
        guard let messageID = message?.messageClientId else { return nil }
        // 获取字典里的model数据
        let model = msgIdDict[messageID]
        return model
    }

    /// 查询model在数据源中的位置index
    func modelIndexWith(model: SessionBaseModel) -> Int? {
        for i in 0 ..< cellModels.count {
            let obj = cellModels[i]
            //if obj.isEqual(model) {
            if obj === model{
                return i
            }
        }
        return nil
    }
    
    /// 通过message 追加model 到数据源
    @discardableResult
    func appendWith(messages: [V2NIMMessage]) -> [Int] {
        let models = modelWithV2(datas: messages)
        // modelWithV2 生成的是反序的
        let indexs = appendWith(models: models.reversed())
        return indexs
    }
    
    /// 通过message 更新数据源的 model
    func updateWith(message: V2NIMMessage) -> [Int]? {
        guard let model = findCellModel(message: message) else { return nil }
        guard let index = modelIndexWith(model: model) else { return nil }
        
        var indexs = [Int]()
        indexs.append(index)
        if needDeriveModel(message: message) {
            if index + 1 < cellModels.count {
                indexs.append(index + 1)
            }
        }
        
        return indexs
    }
    
    // MARK: V2
    /// [V2NIMMessage] -> [SessionBaseModel]
    func modelWithV2(datas:[V2NIMMessage]) -> [SessionBaseModel]{
        var array = [SessionBaseModel]()
        
        for i in 0 ..< datas.count {
            let message = datas[i]
            
            if let messageID = message.messageClientId, msgIdDict[messageID] != nil{
                // 已经存在了
                dlog("☁️⚠️⚠️\(message)已经存在了，应该更新，而不是新创建！⚠️⚠️")
                continue
            }
            
            if let serverExtension = message.serverExtension, serverExtension.count > 0{
                dlog("☁️message___ext___\(serverExtension)")
            }
            
            // Step 通过消息获取初步的cellType
            let info = IMRemoteUtil.dealRemoteInfo(message: message)
            
            // 需要被忽略掉的消息
            guard !ignore(info: info) else {
                continue
            }
            
            // Step 通过类型创建对应的cellModel
            if needDecriveModel(with: info)  { // needDeriveModel(message: message)
                // 从下往上显示：
                // 消息主体(显示在上面👆cell的上方）// 消息主体
                let cellModel = createCellModelWith(type: info.cellType)
                cellModel.baseRemoteInfo = info
                cellModel.isDeriveModel = true
                cellModel.shouldShowLeft = !message.isSelf
                cellModel.v2msg = message
                cellModel.timeStamp = message.createTime
                array.append(cellModel)
                
                if message.messageType == .MESSAGE_TYPE_TEXT {
                    if message.isSelf{
                        let cellModel = createCellModelWith(type: .text)
                        cellModel.baseRemoteInfo = info
                        cellModel.shouldShowLeft = false
                        cellModel.v2msg = message
                        cellModel.timeStamp = message.createTime
                        array.append(cellModel)
                    }else{
                        let cellModel = createCellModelWith(type: .aimsg)
                        cellModel.baseRemoteInfo = info
                        cellModel.shouldShowLeft = true
                        cellModel.v2msg = message
                        cellModel.timeStamp = message.createTime
                        array.append(cellModel)
                    }
                } else if message.messageType == .MESSAGE_TYPE_TIP {
                    let cellModel = createCellModelWith(type: .tips)
                    cellModel.baseRemoteInfo = info
                    cellModel.shouldShowLeft = !message.isSelf
                    cellModel.v2msg = message
                    cellModel.timeStamp = message.createTime
                    array.append(cellModel)
                }else if message.messageType == .MESSAGE_TYPE_CUSTOM{
                    // 自定义消息，承载很多业务消息类型
                    if message.isSelf{
                        let cellModel = createCellModelWith(type: .text)
                        cellModel.baseRemoteInfo = info
                        cellModel.shouldShowLeft = !message.isSelf
                        cellModel.v2msg = message
                        cellModel.timeStamp = message.createTime
                        array.append(cellModel)
                    }else{
                        if info.cellType != .image{
                            let cellModel = createCellModelWith(type: .aimsg)
                            cellModel.baseRemoteInfo = info
                            cellModel.shouldShowLeft = !message.isSelf
                            cellModel.v2msg = message
                            cellModel.timeStamp = message.createTime
                            array.append(cellModel)
                        }
                    }
                }
                
                
                            
                
            } else {
                // 不需要附加一个cell，正常添加
                let cellModel = createCellModelWith(type: info.cellType)
                cellModel.baseRemoteInfo = info
                cellModel.shouldShowLeft = !message.isSelf
                cellModel.v2msg = message
                cellModel.timeStamp = message.createTime
                array.append(cellModel)
            }
        }
        
        
        return array
    }
    
    func createAnAILoadingModel(){
        let cellModel = createCellModelWith(type: .aiLoading)
        cellModel.isDeriveModel = true
        cellModel.shouldShowLeft = true
        cellModel.v2msg = nil
        cellModel.timeStamp = TimeInterval(Date().timeStampInSeconds)
        appendWith(model: cellModel)
    }
    
    func clearAILoadingModel(){
        cellModels.removeAll(where: {$0.cellType == .aiLoading})
    }
    
    
    @discardableResult
    func insertMessagesWith(models: [SessionBaseModel]) -> [Int] {
        if Array.realEmpty(array: models) {
            return []
        }
    
        let count = cellModels.count
        
        for i in 0 ..< models.count {
            let model = models[i]
            if modelIsExist(model: model), !model.isDeriveModel, !model.shouldShowTips {
                continue
            }
            insertMessageWith(model: model, needTime: cellModels.count != count)
        }
        
        var indexs = [Int]()
        for i in 0 ..< cellModels.count - count {
            indexs.append(i)
        }
        return indexs
    }
    
    /// 插入model到数据源
    func insertMessageWith(model: SessionBaseModel, needTime: Bool) {
        // 这条消息上面不能有时间戳，下面必须要有时间戳
        let isCreateTimestampCell = (model.cellType == .create || model.cellType == .tips)
        if isCreateTimestampCell {
            if let theModel = cellModels.first, theModel.cellType != .timeStamp {
                addTimestamp(model: theModel, index: 0)
            }
        } else {
            if !shouldInsertTimestamp(model: model), needTime {
                let model = cellModels.first
                if model?.cellType == .timeStamp {
                    cellModels.removeFirst()
                }
            }
        }
        
        cellModels.insert(model, at: 0)
        setIdIdctObject(model: model)
        if !isCreateTimestampCell {
            addTimestamp(model: model, index: 0)
        }
    }
    
    func loadMessages(completion: @escaping ((_ firstPage: Bool, _ messageDatas: [V2NIMMessage]?, _ error: V2NIMError?) -> Void)){
        let option = V2NIMMessageListOption()
        
        var loadMoreMsgFlag = false
        if let v2Msg = getLastMessageModel()?.v2msg{
            option.anchorMessage = v2Msg
            option.beginTime = v2Msg.createTime
            loadMoreMsgFlag = true
        }
        
        option.conversationId = conversationId
        NIMSDK.shared().v2MessageService.getMessageList(option) {[weak self] messages in
            if let models = self?.modelWithV2(datas: messages){
                //            self?.cellModels = models
                self?.insertMessagesWith(models: models)
                completion(!loadMoreMsgFlag, messages,nil)
            }
        } failure: { error in
            dlog("☁️Get messages error:\(error)")
            completion(!loadMoreMsgFlag, nil,error)
        }

        
    }
}

// MARK: - Messages
extension SessionUtil {
    /// 发送消息
    func sendMessage(message: V2NIMMessage) {
        sendMessage(message: message) { error in
            print(error ?? "")
        }
    }

    /// 发送消息
    func sendMessage(message: V2NIMMessage, completion: @escaping ((_ error: Error?) -> Void)) {
        // See more params in https://doc.yunxin.163.com/messaging2/client-apis/DAxNjk0Mzc?platform=client#V2NIMSendMessageParams
        let param = V2NIMSendMessageParams()
        
        NIMSDK.shared().v2MessageService.send(message, conversationId: conversationId, params: param) { result in
            dlog("☁️✅send message ok \(message.text ?? "")")
        } failure: { error in
            dlog("☁️❌send message failed: \(error)")
            if error.code == 20000{
                CLPurchase.shared.showChatModelsAndIAPEntrySheet()
            }
        }

//        NIMSDK.shared().chatManager.send(message, to: session) { error in
//            completion(error)
//        }
    }

    
}

// MARK: - Test
extension SessionUtil{
    func testModes(completion: @escaping (() -> Void)) {
        var array = [SessionBaseModel]()
        do{
            let cellModel = createCellModelWith(type: .aimsg)
            cellModel.shouldShowLeft = true
            let msg = V2NIMMessage()
            msg.text = "(Watching her parents toast you respectfully, I feel very uncomfortable. After all, she has been standing on the top of the magic capital since she was a child. She has never seen her parents like this, but should I say that he is really handsome?) Are you?"
            cellModel.v2msg = msg
            cellModel.timeStamp = TimeInterval(Date().timeStamp - 1000)
            array.append(cellModel)
        }
        do{
            let cellModel = createCellModelWith(type: .text)
            cellModel.shouldShowLeft = false
            let msg = V2NIMMessage()
            msg.text = "who are you"
            cellModel.v2msg = msg
            cellModel.timeStamp = TimeInterval(Date().timeStamp - 500)
            array.append(cellModel)
        }
        
        cellModels = array
        
        completion()
        
    }
    
    
}
