/*
 * Copyright (c) 2021 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

@objcMembers class PersonalNotesDefaultService : NSObject {
    
    // MARK: - Constants
    private enum AccountDataTypes {
        static let personalNotes = "de.bwi.personal_notes_room"
    }
    
    private var avatarURL = ""
    private let defaultAvatar = "personal_notes_avatar"
    
    private let session:MXSession
    private lazy var serializationService: SerializationServiceType = SerializationService()
    
    static let roomTag = "de.bwi.personal_notes_room"
    
    static func service(_ mxSession: MXSession) -> PersonalNotesDefaultService {
        return PersonalNotesDefaultService(mxSession: mxSession)
    }
    
    init(mxSession: MXSession) {
        self.session = mxSession
    }
        
    func personalNotesRoom() -> PersonalNotesRoom? {
        guard let personalNotesRoomDict = self.session.accountData.accountData(forEventType: AccountDataTypes.personalNotes) as? [String: Any] else {
            return nil
        }
        
        return try? serializationService.deserialize(personalNotesRoomDict)
    }
    
    func initialStateEvent() -> [String: Any] {
        return MXRoomInitialStateEventBuilder().buildAvatarEvent(withAvatarURL: avatarURL)
    }
    
    func creationContent() -> [String:String] {
        return ["m.federate" : "false"]
    }
    
    func roomParameters() -> MXRoomCreationParameters {
        let parameters = MXRoomCreationParameters()
        
        parameters.visibility = kMXRoomDirectoryVisibilityPrivate
        parameters.preset = kMXRoomPresetTrustedPrivateChat
        parameters.name = BWIL10n.bwiNotesRoomTitle
        parameters.initialStateEvents = [MXRoomCreationParameters.initialStateEventForEncryption(withAlgorithm: kMXCryptoMegolmAlgorithm), self.initialStateEvent()]
        parameters.creationContent = self.creationContent()
        
        return parameters
    }
    
    func setRoomId( roomId: String ) -> MXHTTPOperation? {
        // Update only the "widgets" field in the account data
        var personalNotesRoomDict = self.session.accountData.accountData(forEventType: AccountDataTypes.personalNotes) ?? [:]
        
        personalNotesRoomDict[PersonalNotesRoom.CodingKeys.roomId.rawValue] = roomId

        return session.setAccountData(personalNotesRoomDict, forType: AccountDataTypes.personalNotes, success: nil, failure: nil)
    }
    
    func fetchRoomID( completion: @escaping (_ roomId : String?, _ error : Error?) -> Void)  {
        session.matrixRestClient.getAccountData(forType: AccountDataTypes.personalNotes ) { (jsonResponse, error) in
            
            guard let personalNotesDict = jsonResponse as? [String:Any] else {
                completion(nil, error)
                return
            }
            completion(personalNotesDict.first?.value as? String, error)
        }
    }
}
 
extension PersonalNotesDefaultService : PersonalNotesService {

    func personalNotesRoomId() -> String? {
        guard let personalNotesRoom = self.personalNotesRoom() else {
            return nil
        }
        
        return personalNotesRoom.roomId
    }
    
    func createPersonalNotesRoomIfNeeded() {
         
        self.fetchRoomID() { (roomId, error) in
            
            // bwi #5740 don't create room after connection error that is not translated to mxerror
            if let error = error {
                if MXError.isMXError(error) {
                    if let mxError = MXError(nsError: error) {
                        if let errcode = mxError.userInfo["errcode"] as? String {
                            if errcode != kMXErrCodeStringNotFound {
                                // request error, don't create room
                                return
                            }
                        } else {
                            return
                        }
                    }
                } else {
                    return
                }
            }
            
            if roomId == nil {
                self.session.createRoom(parameters: self.roomParameters()) { (response) in
                    switch response {
                    case .success(let room):
                        _ = self.setRoomId(roomId: room.roomId)
               
                        let tagOrder = self.session.tagOrderToBe(at: 0, from: UInt(NSNotFound), withTag: kMXRoomTagFavourite) ?? ""
                        room.replaceTag(kMXRoomTagFavourite, with: kMXRoomTagFavourite, withOrder: tagOrder) { (response) in
                            
                        }
                    case .failure(_ ):
                        MXLog.error("**BWI** Personal Notes creation failure")
                    }
                }
            }
        }
    }
    
    func resetPersonalNotesRoom() {
        session.setAccountData([:], forType: AccountDataTypes.personalNotes, success: nil, failure: nil)
    }
    
    func avatarImageUrl() -> String {
        return self.defaultAvatar
    }
    
    func setAsFavoriteIfNeeded() {
        if let room = self.session.room(withRoomId: self.personalNotesRoomId()) {
            if let accountData = room.accountData {
                if accountData.tags == nil || accountData.tags[kMXRoomTagFavourite] == nil {
                    let tagOrder = self.session.tagOrderToBe(at: 0, from: UInt(NSNotFound), withTag: kMXRoomTagFavourite) ?? ""
                    room.replaceTag(kMXRoomTagFavourite, with: kMXRoomTagFavourite, withOrder: tagOrder) { (response) in
                        // check old settings
                        let layoutSettings = AllChatsLayoutSettingsManager.shared.allChatLayoutSettings
                        PersonalNotesSettings().personalNotesVisible = layoutSettings.sections.contains(.bwiPersonalNotes)
                    }
                }
            }
        }
    }
}
