// 
// Copyright 2022 New Vector Ltd
//
// 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 UIKit
import MatrixSDK

enum AllChatsSpaceActionProviderOption {
    case invitePeople
    case spaceMembers
    case spaceSettings
    case leaveSpace
}

protocol AllChatsSpaceActionProviderDelegate: AnyObject {
    func allChatsSpaceActionProvider(_ actionProvider: AllChatsSpaceActionProvider, didSelect option: AllChatsSpaceActionProviderOption)
}

/// `AllChatsSpaceActionProvider` provides the menu for accessing space options according to the current space
class AllChatsSpaceActionProvider {
    
    // MARK: - Properties
    
    weak var delegate: AllChatsSpaceActionProviderDelegate?
    
    // MARK: - Private

    private var currentSpace: MXSpace? {
        didSet {
            spaceName = currentSpace?.summary?.displayName ?? VectorL10n.spaceTag
        }
    }
    private var spaceName: String = VectorL10n.spaceTag
    private var isInviteAvailable: Bool = false

    // MARK: - RoomActionProviderProtocol
    
    var menu: UIMenu {
        guard currentSpace != nil else {
            return UIMenu(title: "", children: [])
        }
        
        return UIMenu(title: "", children: [
            UIMenu(title: "", options: .displayInline, children: [
                self.spaceSettingsAction,
                self.spaceMembersAction,
                self.invitePeopleAction
            ]),
            self.leaveSpaceAction
        ])
    }
    
    // MARK: - Public
    
    /// Returns an instance of the updated menu accordingly to the given parameters.
    ///
    /// Some menu items can be disabled depending on the required power levels of the `parentSpace`. Therefore, `updateMenu()` first returns a temporary context menu
    /// with all sensible items disabled, asynchronously fetches power levels of the `parentSpace`, then gives a new instance of the menu with, potentially, all sensible items
    /// enabled via the `completion` callback.
    ///
    /// - Parameters:
    ///     - session: The current `MXSession` instance
    ///     - space: The current space (`nil` for home space)
    ///     - completion: callback called once the power levels of the `parentSpace` have been fetched and the menu items have been computed accordingly.
    /// - Returns: If the `parentSpace` is `nil`, the context menu, the temporary context menu otherwise.
    func updateMenu(with session: MXSession?, space: MXSpace?, completion: @escaping (UIMenu) -> Void) -> UIMenu {
        self.currentSpace = space
        isInviteAvailable = false
        
        guard let currentSpace = currentSpace, let spaceRoom = currentSpace.room, let session = session else {
            return self.menu
        }
        
        spaceRoom.state { [weak self] roomState in
            guard let self = self else { return }
            
            guard let powerLevels = roomState?.powerLevels, let userId = session.myUserId else {
                return
            }
            let userPowerLevel = powerLevels.powerLevelOfUser(withUserID: userId)

            self.isInviteAvailable = userPowerLevel >= powerLevels.invite
            
            completion(self.menu)
        }
        
        return self.menu
    }
    
    // MARK: - Private
    
    private var invitePeopleAction: UIAction {
        UIAction(title: VectorL10n.inviteTo(spaceName),
                 image: UIImage(systemName: "square.and.arrow.up"),
                 attributes: isInviteAvailable ? [] : .disabled) { [weak self] action in
            guard let self = self else { return }
            
            self.delegate?.allChatsSpaceActionProvider(self, didSelect: .invitePeople)
        }
    }
    
    private var spaceMembersAction: UIAction {
        UIAction(title: VectorL10n.roomDetailsPeople,
                 image: UIImage(systemName: "person")) { [weak self] action in
            guard let self = self else { return }
            
            self.delegate?.allChatsSpaceActionProvider(self, didSelect: .spaceMembers)
        }
    }
    
    private var spaceSettingsAction: UIAction {
        UIAction(title: VectorL10n.allChatsEditMenuSpaceSettings,
                 image: UIImage(systemName: "gearshape")) { [weak self] action in
            guard let self = self else { return }
            
            self.delegate?.allChatsSpaceActionProvider(self, didSelect: .spaceSettings)
        }
    }
    
    private var leaveSpaceAction: UIAction {
        UIAction(title: VectorL10n.allChatsEditMenuLeaveSpace(spaceName),
                 image: UIImage(systemName: "rectangle.portrait.and.arrow.right.fill"),
                 attributes: .destructive) { [weak self] action in
            guard let self = self else { return }
            
            self.delegate?.allChatsSpaceActionProvider(self, didSelect: .leaveSpace)
        }
    }
}
