final class MentionSelectionView : UIView, UITableViewDataSource, UITableViewDelegate {
    var candidates: [Mention] = [] {
        didSet {
            tableView.isScrollEnabled = (candidates.count > 4)
            tableView.reloadData()
        }
    }
    var openGroupServer: String?
    var openGroupChannel: UInt64?
    var openGroupRoom: String?
    weak var delegate: MentionSelectionViewDelegate?

    // MARK: Components
    lazy var tableView: UITableView = { // TODO: Make this private
        let result = UITableView()
        result.dataSource = self
        result.delegate = self
        result.register(Cell.self, forCellReuseIdentifier: "Cell")
        result.separatorStyle = .none
        result.backgroundColor = .clear
        result.showsVerticalScrollIndicator = false
        return result
    }()

    // MARK: Initialization
    override init(frame: CGRect) {
        super.init(frame: frame)
        setUpViewHierarchy()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setUpViewHierarchy()
    }

    private func setUpViewHierarchy() {
        // Table view
        addSubview(tableView)
        tableView.pin(to: self)
        // Top separator
        let topSeparator = UIView()
        topSeparator.backgroundColor = Colors.separator
        topSeparator.set(.height, to: Values.separatorThickness)
        addSubview(topSeparator)
        topSeparator.pin(.leading, to: .leading, of: self)
        topSeparator.pin(.top, to: .top, of: self)
        topSeparator.pin(.trailing, to: .trailing, of: self)
        // Bottom separator
        let bottomSeparator = UIView()
        bottomSeparator.backgroundColor = Colors.separator
        bottomSeparator.set(.height, to: Values.separatorThickness)
        addSubview(bottomSeparator)
        bottomSeparator.pin(.leading, to: .leading, of: self)
        bottomSeparator.pin(.trailing, to: .trailing, of: self)
        bottomSeparator.pin(.bottom, to: .bottom, of: self)
    }

    // MARK: Data
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return candidates.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! Cell
        let mentionCandidate = candidates[indexPath.row]
        cell.mentionCandidate = mentionCandidate
        cell.openGroupServer = openGroupServer
        cell.openGroupChannel = openGroupChannel
        cell.openGroupRoom = openGroupRoom
        cell.separator.isHidden = (indexPath.row == (candidates.count - 1))
        return cell
    }

    // MARK: Interaction
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let mentionCandidate = candidates[indexPath.row]
        delegate?.handleMentionSelected(mentionCandidate, from: self)
    }
}

// MARK: - Cell

private extension MentionSelectionView {

    final class Cell : UITableViewCell {
        var mentionCandidate = Mention(publicKey: "", displayName: "") { didSet { update() } }
        var openGroupServer: String?
        var openGroupChannel: UInt64?
        var openGroupRoom: String?

        // MARK: Components
        private lazy var profilePictureView = ProfilePictureView()

        private lazy var moderatorIconImageView = UIImageView(image: #imageLiteral(resourceName: "Crown"))

        private lazy var displayNameLabel: UILabel = {
            let result = UILabel()
            result.textColor = Colors.text
            result.font = .systemFont(ofSize: Values.smallFontSize)
            result.lineBreakMode = .byTruncatingTail
            return result
        }()

        lazy var separator: UIView = {
            let result = UIView()
            result.backgroundColor = Colors.separator
            result.set(.height, to: Values.separatorThickness)
            return result
        }()

        // MARK: Initialization
        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            setUpViewHierarchy()
        }

        required init?(coder: NSCoder) {
            super.init(coder: coder)
            setUpViewHierarchy()
        }

        private func setUpViewHierarchy() {
            // Cell background color
            backgroundColor = .clear
            // Highlight color
            let selectedBackgroundView = UIView()
            selectedBackgroundView.backgroundColor = .clear
            self.selectedBackgroundView = selectedBackgroundView
            // Profile picture image view
            let profilePictureViewSize = Values.smallProfilePictureSize
            profilePictureView.set(.width, to: profilePictureViewSize)
            profilePictureView.set(.height, to: profilePictureViewSize)
            profilePictureView.size = profilePictureViewSize
            // Main stack view
            let mainStackView = UIStackView(arrangedSubviews: [ profilePictureView, displayNameLabel ])
            mainStackView.axis = .horizontal
            mainStackView.alignment = .center
            mainStackView.spacing = Values.mediumSpacing
            mainStackView.set(.height, to: profilePictureViewSize)
            contentView.addSubview(mainStackView)
            mainStackView.pin(.leading, to: .leading, of: contentView, withInset: Values.mediumSpacing)
            mainStackView.pin(.top, to: .top, of: contentView, withInset: Values.smallSpacing)
            contentView.pin(.trailing, to: .trailing, of: mainStackView, withInset: Values.mediumSpacing)
            contentView.pin(.bottom, to: .bottom, of: mainStackView, withInset: Values.smallSpacing)
            mainStackView.set(.width, to: UIScreen.main.bounds.width - 2 * Values.mediumSpacing)
            // Moderator icon image view
            moderatorIconImageView.set(.width, to: 20)
            moderatorIconImageView.set(.height, to: 20)
            contentView.addSubview(moderatorIconImageView)
            moderatorIconImageView.pin(.trailing, to: .trailing, of: profilePictureView, withInset: 1)
            moderatorIconImageView.pin(.bottom, to: .bottom, of: profilePictureView, withInset: 4.5)
            // Separator
            addSubview(separator)
            separator.pin(.leading, to: .leading, of: self)
            separator.pin(.trailing, to: .trailing, of: self)
            separator.pin(.bottom, to: .bottom, of: self)
        }

        // MARK: Updating
        private func update() {
            displayNameLabel.text = mentionCandidate.displayName
            profilePictureView.publicKey = mentionCandidate.publicKey
            profilePictureView.update()
            if let server = openGroupServer, let room = openGroupRoom {
                let isUserModerator = OpenGroupAPIV2.isUserModerator(mentionCandidate.publicKey, for: room, on: server)
                moderatorIconImageView.isHidden = !isUserModerator
            } else {
                moderatorIconImageView.isHidden = true
            }
        }
    }
}

// MARK: - Delegate

protocol MentionSelectionViewDelegate : class {

    func handleMentionSelected(_ mention: Mention, from view: MentionSelectionView)
}