//
/*
 * Copyright (c) 2023 BWI GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import Foundation
import MatrixSDK

@objc extension MXRoom {
    
    // Federation status for room, "isFederated" flag + serverACL
    func getFederationStatus(completion: ((_ isFederated:Bool) -> Void)?)  {
        // #5715 do not show federation for invites
        if (summary != nil && summary.membership == .invite) {
            if let roomId = summary.roomId {
                completion?(isRoomIdFederated(roomId: roomId))
            } else {
                completion?(false)
            }
        } else {
            var federationStatus = true
            // Get federated flag
            getFederatedFlag { isFederated in
                federationStatus = isFederated
                if federationStatus {
                    // Check Server ACLs
                    self.getCurrentRoomServerACLSettings { serverACL in
                        if let serverACL = serverACL {
                            if self.mxSession != nil && self.mxSession.myUser != nil {
                                let myUserId = self.mxSession.myUser.userId ?? ""
                                let myUserIdComponents = myUserId.components(separatedBy: ":")
                                if serverACL != "*" && myUserIdComponents.count == 2 && serverACL == myUserIdComponents.last ?? "" {
                                    federationStatus = false
                                }
                            }
                        }
                        completion?(federationStatus)
                    }
                } else {
                    completion?(federationStatus)
                }
            }
        }
    }
    
    
    func isDMFederated() -> Bool {
        var isFederated: Bool = false
        // Check if the user is from the same homeserver
        if let memberUserId = self.directUserId {
            if self.mxSession != nil && self.mxSession.myUser != nil {
                if let myUserId = self.mxSession.myUser.userId {
                    let memberUserIdComponents = memberUserId.components(separatedBy: ":")
                    let myUserIdComponents = myUserId.components(separatedBy: ":")
                    if memberUserIdComponents.count == 2 && myUserIdComponents.count == 2
                        && memberUserIdComponents.last !=  myUserIdComponents.last {
                        isFederated = true
                    }
                }
            }
        }
        return isFederated
    }
    
    func isRoomCurrentlyFederated(completion: ((_ isFederated: Bool) -> Void)?)  {
        self.getCurrentRoomServerACLSettings { serverACL in
            if let serverACL = serverACL {
                if serverACL.elementsEqual("*") {
                    completion?(true)
                }
            }
            completion?(false)
        }
    }

    func isRoomMemberFederated(_ userId: String) -> Bool {
        var isFederated: Bool = false
        // Check if the user is from the same homeserver
        if self.mxSession != nil && self.mxSession.myUser != nil {
            if let myUserId = self.mxSession.myUser.userId {
                let memberUserIdComponents = userId.components(separatedBy: ":")
                let myUserIdComponents = myUserId.components(separatedBy: ":")
                if memberUserIdComponents.count == 2 && myUserIdComponents.count == 2
                    && memberUserIdComponents.last !=  myUserIdComponents.last {
                    isFederated = true
                }
            }
        }
        return isFederated
    }
    
    // bwi #5395 am i a federated member
    func amiFederated() -> Bool {
        var isFederated: Bool = false
        // Check if the room is from the same homeserver
        if self.mxSession != nil && self.mxSession.myUser != nil {
            if let myUserId = self.mxSession.myUser.userId {
                let roomUserIdComponents = self.roomId.components(separatedBy: ":")
                let myUserIdComponents = myUserId.components(separatedBy: ":")
                if roomUserIdComponents.count == 2 && myUserIdComponents.count == 2
                    && roomUserIdComponents.last !=  myUserIdComponents.last {
                    isFederated = true
                }
            }
        }
        return isFederated
    }
    
    // Get "isFederated" flag for room, default == true
    func getFederatedFlag(completion: ((_ isFederated: Bool) -> Void)?) {
        state { state in
            var isFederated = true
            // Search for federate flag. If the flag is not found, default value is true
            if let events = state?.stateEvents(with: .roomCreate) {
                for event in events {
                    if let federateContentValue = event.wireContent["m.federate"] {
                        isFederated = federateContentValue as? Bool ?? true
                    }
                }
            }
            completion?(isFederated)
        }
    }
    
    // Get serverACL for room
    func getCurrentRoomServerACLSettings(completion: ((_ serverACL: String?)-> Void)?) {
        state { state in
            if let events = state?.stateEvents(with: .roomServerACL) {
                if let event = events.last {
                    if let allowedServerList = event.wireContent["allow"] as? [String] {
                        if allowedServerList.count == 1 {
                            completion?(allowedServerList[0])
                        } else {
                            // No ServerACL settings found
                            completion?(nil)
                        }
                    } else {
                        // No ServerACL settings found
                        completion?(nil)
                    }
                } else {
                    // No ServerACL settings found
                    completion?(nil)
                }
            } else {
                // No ServerACL settings found
                completion?(nil)
            }
        }
    }
    
    // Create map for content json with boolean
    func createServerACL(isFederated: Bool) -> [String:Any] {
        var serverACL: String = ""
        if isFederated {
            serverACL = "*"
        } else {
            if let myUserIDComponents = self.mxSession.myUserId?.components(separatedBy: ":")
            {
                if myUserIDComponents.count == 2 {
                    serverACL = myUserIDComponents[1]
                }
            }
        }
        return createServerACLContent(serverACL: serverACL)
    }
    
    // Create map for content json with serverACL string
    func createServerACLContent(serverACL: String) -> [String:Any] {
        var content: [String:Any] = [String:Any]()
        var serverACLList: [String] = [String]()
        serverACLList.append(serverACL)
        content.updateValue(serverACLList, forKey: "allow")
        content.updateValue(false, forKey: "allow_ip_literals")
        
        return content
    }
    
    // #5383 Check if no canonical alias exists, create alias from name and timestamp and add as canonical alias
    func setAliasIfNeeded(roomName: String?) {
        Task {
            do {
                var needsAlias: Bool = false
                let state = try await state()
                
                // Check if canonical exists
                if let canonicalAlias = state.canonicalAlias {
                    if canonicalAlias.isEmpty {
                        needsAlias = true
                    } else {
                        needsAlias = false
                    }
                } else {
                    needsAlias = true
                }
                if needsAlias {
                    if let roomName = roomName {
                        if !roomName.isEmpty {
                            // Create new alias
                            var newAlias = MXTools.createAlias(from: roomName)
                            // Generate local alias
                            newAlias = MXTools.fullLocalAlias(from: newAlias, with: mxSession)
                            
                            // Add local alias
                            addAlias(newAlias) { [self] response in
                                if response.isSuccess {
                                    // Set new alias as canonical alias
                                    setCanonicalAlias(newAlias) { response in
                                        return
                                    }
                                }
                                return
                            }
                        }
                    }
                }
            } catch { return }
        }
    }
    
    func isRoomIdFederated(roomId: String) -> Bool {
        var isFederated: Bool = false
        // Check if the room is from the same homeserver
        if self.mxSession != nil && self.mxSession.myUser != nil {
            if let myUserId = self.mxSession.myUser.userId {
                let memberUserIdComponents = roomId.components(separatedBy: ":")
                let myUserIdComponents = myUserId.components(separatedBy: ":")
                if memberUserIdComponents.count == 2 && myUserIdComponents.count == 2
                    && memberUserIdComponents.last !=  myUserIdComponents.last {
                    isFederated = true
                }
            }
        }
        return isFederated
    }
}
