// 
// Copyright 2021 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 Foundation


class SpaceMenuViewController: UIViewController {
    
    // MARK: - Constants
    
    private enum Constants {
        static let estimatedRowHeight: CGFloat = 64.0
    }
    
    // MARK: Private

    private var theme: Theme!
    private var session: MXSession!
    private var spaceId: String!
    private var viewModel: SpaceMenuViewModelType!
    private var errorPresenter: MXKErrorPresentation!
    private var activityPresenter: ActivityIndicatorPresenter!

    // MARK: Outlets

    @IBOutlet private weak var avatarView: SpaceAvatarView!
    @IBOutlet private weak var titleLabel: UILabel!
    @IBOutlet private weak var subtitleLabel: UILabel!
    @IBOutlet private weak var closeButton: UIButton!
    @IBOutlet private weak var tableView: UITableView!
    @IBOutlet private weak var bottomMargin: NSLayoutConstraint!

    // MARK: - Setup
    
    class func instantiate(forSpaceWithId spaceId: String, matrixSession: MXSession, viewModel: SpaceMenuViewModelType!) -> SpaceMenuViewController {
        let viewController = StoryboardScene.SpaceMenuViewController.initialScene.instantiate()
        viewController.session = matrixSession
        viewController.spaceId = spaceId
        viewController.viewModel = viewModel
        viewController.theme = ThemeService.shared().theme
        return viewController
    }
    
    // MARK: - Life cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        
        self.setupViews()
        self.activityPresenter = ActivityIndicatorPresenter()
        self.errorPresenter = MXKErrorAlertPresentation()

        self.registerThemeServiceDidChangeThemeNotification()
        self.update(theme: self.theme)
        
        self.viewModel.viewDelegate = self
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        AnalyticsScreenTracker.trackScreen(.spaceMenu)
    }
    
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return self.theme.statusBarStyle
    }
    
    override var preferredContentSize: CGSize {
        get {
            return CGSize(width: 320, height: self.tableView.frame.minY + Constants.estimatedRowHeight * CGFloat(self.viewModel.menuItems.count) + self.bottomMargin.constant)
        }
        set {
            super.preferredContentSize = newValue
        }
    }
    
    // MARK: - IBActions
    
    @IBAction private func closeAction(sender: UIButton) {
        self.viewModel.process(viewAction: .dismiss)
    }
    
    // MARK: - Private
    
    private func update(theme: Theme) {
        self.theme = theme
        
        self.view.backgroundColor = theme.colors.background
        
        self.titleLabel.textColor = theme.colors.primaryContent
        self.titleLabel.font = theme.fonts.title3SB
        self.subtitleLabel.textColor = theme.colors.secondaryContent
        self.subtitleLabel.font = theme.fonts.caption1
        self.closeButton.backgroundColor = theme.roomInputTextBorder
        self.closeButton.tintColor = theme.noticeSecondaryColor
        
        if self.spaceId == SpaceListViewModel.Constants.homeSpaceId {
            let defaultAsset = ThemeService.shared().isCurrentThemeDark() ? Asset.Images.spaceHomeIconDark : Asset.Images.spaceHomeIconLight
            let avatarViewData = AvatarViewData(matrixItemId: self.spaceId, displayName: nil, avatarUrl: nil, mediaManager: session.mediaManager, fallbackImage: .image(defaultAsset.image, .center))
            self.avatarView.fill(with: avatarViewData)
        }
    }
    
    private func registerThemeServiceDidChangeThemeNotification() {
        NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
    }
    
    @objc private func themeDidChange() {
        self.update(theme: ThemeService.shared().theme)
    }
    
    private func setupViews() {
        setupTableView()
        
        if self.spaceId == SpaceListViewModel.Constants.homeSpaceId {
            self.titleLabel.text = VectorL10n.titleHome
            self.subtitleLabel.text = VectorL10n.settingsTitle
            
            return
        }

        guard let space = self.session.spaceService.getSpace(withId: self.spaceId), let summary = space.summary else {
            MXLog.error("[SpaceMenuViewController] setupViews: no space found")
            return
        }
        
        let avatarViewData = AvatarViewData(matrixItemId: summary.roomId, displayName: summary.displayName, avatarUrl: summary.avatar, mediaManager: self.session.mediaManager, fallbackImage: .matrixItem(summary.roomId, summary.displayName))

        self.titleLabel.text = space.summary?.displayName
        // TODO: display members instead once done on android
//        self.subtitleLabel.text = space.membersId.count == 1 ? VectorL10n.roomTitleOneMember :
//            VectorL10n.roomTitleMembers("\(space.membersId.count)")
        self.subtitleLabel.text = summary.topic
        self.avatarView.fill(with: avatarViewData)
        
        self.closeButton.layer.masksToBounds = true
        self.closeButton.layer.cornerRadius = self.closeButton.bounds.height / 2
    }
    
    private func setupTableView() {
        self.tableView.separatorStyle = .none
        self.tableView.rowHeight = UITableView.automaticDimension
        self.tableView.estimatedRowHeight = Constants.estimatedRowHeight
        self.tableView.allowsSelection = true
        self.tableView.register(cellType: SpaceMenuListViewCell.self)
        self.tableView.register(cellType: SpaceMenuSwitchViewCell.self)
        self.tableView.tableFooterView = UIView()
    }
    
    private func render(viewState: SpaceMenuViewState) {
        switch viewState {
        case .loading:
            self.renderLoading()
        case .loaded:
            self.renderLoaded()
        case .leaveOptions(let displayName, let isAdmin):
            self.renderLeaveOptions(displayName: displayName, isAdmin: isAdmin)
        case .error(let error):
            self.render(error: error)
        case .deselect:
            self.renderDeselect()
        }
    }
    
    private func renderLoading() {
        self.activityPresenter.presentActivityIndicator(on: self.view, animated: true)
    }
    
    private func renderLoaded() {
        self.activityPresenter.removeCurrentActivityIndicator(animated: true)
        self.renderDeselect()
    }
    
    private func renderLeaveOptions(displayName: String, isAdmin: Bool) {
        var message = VectorL10n.leaveSpaceMessage(displayName)

        if isAdmin {
            message += "\n\n" + VectorL10n.leaveSpaceMessageAdminWarning
        }

        let alert = UIAlertController(title: VectorL10n.leaveSpaceTitle(displayName), message: message, preferredStyle: .alert)

        alert.addAction(UIAlertAction(title: VectorL10n.leaveSpaceOnlyAction, style: .default, handler: { [weak self] action in
            self?.viewModel.process(viewAction: .leaveSpaceAndKeepRooms)
        }))
        alert.addAction(UIAlertAction(title: VectorL10n.leaveSpaceAndAllRoomsAction, style: .destructive, handler: { [weak self] action in
            self?.viewModel.process(viewAction: .leaveSpaceAndLeaveRooms)
        }))
        alert.addAction(UIAlertAction(title: VectorL10n.cancel, style: .cancel, handler: { [weak self] action in
            self?.renderDeselect()
        }))
        
        self.present(alert, animated: true, completion: nil)
    }
    
    private func render(error: Error) {
        self.activityPresenter.removeCurrentActivityIndicator(animated: true)
        self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil)
    }
    
    private func renderDeselect() {
        if let selectedRow = self.tableView.indexPathForSelectedRow {
            self.tableView.deselectRow(at: selectedRow, animated: true)
        }
    }
}

// MARK: - SlidingModalPresentable

extension SpaceMenuViewController: SlidingModalPresentable {
    
    func allowsDismissOnBackgroundTap() -> Bool {
        return true
    }
    
    func layoutHeightFittingWidth(_ width: CGFloat) -> CGFloat {
        return self.preferredContentSize.height
    }
    
}

// MARK: - SpaceMenuViewModelViewDelegate

extension SpaceMenuViewController: SpaceMenuViewModelViewDelegate {
    func spaceMenuViewModel(_ viewModel: SpaceMenuViewModelType, didUpdateViewState viewSate: SpaceMenuViewState) {
        self.render(viewState: viewSate)
    }
}

// MARK: - UITableViewDataSource

extension SpaceMenuViewController: UITableViewDataSource {
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return viewModel.menuItems.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let viewData = viewModel.menuItems[indexPath.row]
        
        let cell = viewData.style == .toggle ? tableView.dequeueReusableCell(for: indexPath, cellType: SpaceMenuSwitchViewCell.self) :
                        tableView.dequeueReusableCell(for: indexPath, cellType: SpaceMenuListViewCell.self)
        
        if let cell = cell as? SpaceMenuCell {
            cell.update(theme: self.theme)
            cell.update(with: viewData)
        }
        
        return cell
    }
}

// MARK: - UITableViewDelegate

extension SpaceMenuViewController: UITableViewDelegate {
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.viewModel.process(viewAction: .selectRow(at: indexPath))
    }
}
