import Foundation
import UIKit
import Display
import ComponentFlow
import MultilineTextComponent
import TelegramPresentationData
import TelegramCore
import AccountContext
import ListSectionComponent
import ListActionItemComponent
import PeerListItemComponent
import ViewControllerComponent
import BundleIconComponent
import AvatarNode
import SwiftSignalKit

final class BusinessRecipientListScreenComponent: Component {
    typealias EnvironmentType = ViewControllerComponentContainer.Environment
    
    let context: AccountContext
    let initialData: BusinessRecipientListScreen.InitialData
    let mode: BusinessRecipientListScreen.Mode
    let update: (BusinessRecipientListScreenComponent.PeerList) -> Void

    init(
        context: AccountContext,
        initialData: BusinessRecipientListScreen.InitialData,
        mode: BusinessRecipientListScreen.Mode,
        update: @escaping (BusinessRecipientListScreenComponent.PeerList) -> Void
    ) {
        self.context = context
        self.initialData = initialData
        self.mode = mode
        self.update = update
    }

    static func ==(lhs: BusinessRecipientListScreenComponent, rhs: BusinessRecipientListScreenComponent) -> Bool {
        if lhs.context !== rhs.context {
            return false
        }

        return true
    }
    
    private final class ScrollView: UIScrollView {
        override func touchesShouldCancel(in view: UIView) -> Bool {
            return true
        }
    }
    
    struct PeerList {
        enum Category: Int {
            case newChats = 0
            case existingChats = 1
            case contacts = 2
            case nonContacts = 3
        }
        
        struct Peer {
            var peer: EnginePeer
            var isContact: Bool
            
            init(peer: EnginePeer, isContact: Bool) {
                self.peer = peer
                self.isContact = isContact
            }
        }
        
        var categories: Set<Category>
        var peers: [Peer]
        
        init(categories: Set<Category>, peers: [Peer]) {
            self.categories = categories
            self.peers = peers
        }
    }
    
    final class View: UIView, UIScrollViewDelegate {
        private let topOverscrollLayer = SimpleLayer()
        private let scrollView: ScrollView
        
        private let navigationTitle = ComponentView<Empty>()
        private let excludedSection = ComponentView<Empty>()
        private let clearSection = ComponentView<Empty>()
        
        private var isUpdating: Bool = false
        
        private var component: BusinessRecipientListScreenComponent?
        private(set) weak var state: EmptyComponentState?
        private var environment: EnvironmentType?
        
        private var peerList = PeerList(
            categories: Set(),
            peers: []
        )
        
        override init(frame: CGRect) {
            self.scrollView = ScrollView()
            self.scrollView.showsVerticalScrollIndicator = true
            self.scrollView.showsHorizontalScrollIndicator = false
            self.scrollView.scrollsToTop = false
            self.scrollView.delaysContentTouches = false
            self.scrollView.canCancelContentTouches = true
            self.scrollView.contentInsetAdjustmentBehavior = .never
            if #available(iOS 13.0, *) {
                self.scrollView.automaticallyAdjustsScrollIndicatorInsets = false
            }
            self.scrollView.alwaysBounceVertical = true
            
            super.init(frame: frame)
            
            self.scrollView.delegate = self
            self.addSubview(self.scrollView)
            
            self.scrollView.layer.addSublayer(self.topOverscrollLayer)
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        deinit {
        }

        func scrollToTop() {
            self.scrollView.setContentOffset(CGPoint(), animated: true)
        }
        
        func attemptNavigation(complete: @escaping () -> Void) -> Bool {
            guard let component = self.component else {
                return true
            }
            
            component.update(self.peerList)
            
            return true
        }
        
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            self.updateScrolling(transition: .immediate)
        }
        
        var scrolledUp = true
        private func updateScrolling(transition: Transition) {
            let navigationRevealOffsetY: CGFloat = 0.0
            
            let navigationAlphaDistance: CGFloat = 16.0
            let navigationAlpha: CGFloat = max(0.0, min(1.0, (self.scrollView.contentOffset.y - navigationRevealOffsetY) / navigationAlphaDistance))
            if let controller = self.environment?.controller(), let navigationBar = controller.navigationBar {
                transition.setAlpha(layer: navigationBar.backgroundNode.layer, alpha: navigationAlpha)
                transition.setAlpha(layer: navigationBar.stripeNode.layer, alpha: navigationAlpha)
            }
            
            var scrolledUp = false
            if navigationAlpha < 0.5 {
                scrolledUp = true
            } else if navigationAlpha > 0.5 {
                scrolledUp = false
            }
            
            if self.scrolledUp != scrolledUp {
                self.scrolledUp = scrolledUp
                if !self.isUpdating {
                    self.state?.updated()
                }
            }
            
            if let navigationTitleView = self.navigationTitle.view {
                transition.setAlpha(view: navigationTitleView, alpha: 1.0)
            }
        }
        
        static func makePeerListSetupScreen(context: AccountContext, mode: BusinessRecipientListScreen.Mode, initialPeerList: BusinessRecipientListScreenComponent.PeerList, completion: @escaping (BusinessRecipientListScreenComponent.PeerList) -> Void) -> ViewController {
            let presentationData = context.sharedContext.currentPresentationData.with({ $0 })
            
            enum AdditionalCategoryId: Int {
                case existingChats
                case newChats
                case contacts
                case nonContacts
            }
            
            let hasAccessToAllChatsByDefault: Bool
            let isExclude: Bool
            switch mode {
            case .excludeExceptions:
                hasAccessToAllChatsByDefault = true
                isExclude = false
            case .includeExceptions:
                hasAccessToAllChatsByDefault = false
                isExclude = false
            case .excludeUsers:
                hasAccessToAllChatsByDefault = false
                isExclude = true
            }
            
            let additionalCategories: [ChatListNodeAdditionalCategory]
            var selectedCategories = Set<Int>()
            if isExclude {
                additionalCategories = []
            } else {
                additionalCategories = [
                    ChatListNodeAdditionalCategory(
                        id: hasAccessToAllChatsByDefault ? AdditionalCategoryId.existingChats.rawValue : AdditionalCategoryId.newChats.rawValue,
                        icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: hasAccessToAllChatsByDefault ? "Chat List/Filters/Chats" : "Chat List/Filters/NewChats"), color: .white), cornerRadius: 12.0, color: .purple),
                        smallIcon: generateAvatarImage(size: CGSize(width: 22.0, height: 22.0), icon: generateTintedImage(image: UIImage(bundleImageName: hasAccessToAllChatsByDefault ? "Chat List/Filters/Chats" : "Chat List/Filters/NewChats"), color: .white), iconScale: 0.6, cornerRadius: 6.0, circleCorners: true, color: .purple),
                        title: hasAccessToAllChatsByDefault ? presentationData.strings.BusinessMessageSetup_Recipients_CategoryExistingChats : presentationData.strings.BusinessMessageSetup_Recipients_CategoryNewChats
                    ),
                    ChatListNodeAdditionalCategory(
                        id: AdditionalCategoryId.contacts.rawValue,
                        icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/Filters/Contact"), color: .white), cornerRadius: 12.0, color: .blue),
                        smallIcon: generateAvatarImage(size: CGSize(width: 22.0, height: 22.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/Filters/Contact"), color: .white), iconScale: 0.6, cornerRadius: 6.0, circleCorners: true, color: .blue),
                        title: presentationData.strings.BusinessMessageSetup_Recipients_CategoryContacts
                    ),
                    ChatListNodeAdditionalCategory(
                        id: AdditionalCategoryId.nonContacts.rawValue,
                        icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/Filters/User"), color: .white), cornerRadius: 12.0, color: .yellow),
                        smallIcon: generateAvatarImage(size: CGSize(width: 22.0, height: 22.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/Filters/User"), color: .white), iconScale: 0.6, cornerRadius: 6.0, circleCorners: true, color: .yellow),
                        title: presentationData.strings.BusinessMessageSetup_Recipients_CategoryNonContacts
                    )
                ]
            }
            if !isExclude {
                for category in initialPeerList.categories {
                    switch category {
                    case .existingChats:
                        selectedCategories.insert(AdditionalCategoryId.existingChats.rawValue)
                    case .newChats:
                        selectedCategories.insert(AdditionalCategoryId.newChats.rawValue)
                    case .contacts:
                        selectedCategories.insert(AdditionalCategoryId.contacts.rawValue)
                    case .nonContacts:
                        selectedCategories.insert(AdditionalCategoryId.nonContacts.rawValue)
                    }
                }
            }
            
            let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(ContactMultiselectionControllerMode.ChatSelection(
                title: presentationData.strings.ChatbotSetup_Recipients_SelectionTitle,
                searchPlaceholder: presentationData.strings.ChatListFilter_AddChatsSearchPlaceholder,
                selectedChats: Set(initialPeerList.peers.map(\.peer.id)),
                additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories),
                chatListFilters: nil,
                onlyUsers: true
            )), filters: [], alwaysEnabled: true, limit: 100, reachedLimit: { _ in
            }))
            controller.navigationPresentation = .modal
            
            let _ = (controller.result
            |> take(1)
            |> deliverOnMainQueue).startStandalone(next: { [weak controller] result in
                guard case let .result(rawPeerIds, additionalCategoryIds) = result else {
                    controller?.dismiss()
                    return
                }
                
                let peerIds = rawPeerIds.compactMap { id -> EnginePeer.Id? in
                    switch id {
                    case let .peer(id):
                        return id
                    case .deviceContact:
                        return nil
                    }
                }
                
                let _ = (context.engine.data.get(
                    EngineDataMap(
                        peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))
                    ),
                    EngineDataMap(
                        peerIds.map(TelegramEngine.EngineData.Item.Peer.IsContact.init(id:))
                    )
                )
                |> deliverOnMainQueue).start(next: { peerMap, isContactMap in
                    var peerList = BusinessRecipientListScreenComponent.PeerList(categories: Set(), peers: [])
                    
                    if !isExclude {
                        let mappedCategories = additionalCategoryIds.compactMap { item -> PeerList.Category? in
                            switch item {
                            case AdditionalCategoryId.existingChats.rawValue:
                                return .existingChats
                            case AdditionalCategoryId.newChats.rawValue:
                                return .newChats
                            case AdditionalCategoryId.contacts.rawValue:
                                return .contacts
                            case AdditionalCategoryId.nonContacts.rawValue:
                                return .nonContacts
                            default:
                                return nil
                            }
                        }
                        
                        peerList.categories = Set(mappedCategories)
                        
                        peerList.peers.removeAll()
                        for id in peerIds {
                            guard let maybePeer = peerMap[id], let peer = maybePeer else {
                                continue
                            }
                            peerList.peers.append(PeerList.Peer(
                                peer: peer,
                                isContact: isContactMap[id] ?? false
                            ))
                        }
                        peerList.peers.sort(by: { lhs, rhs in
                            return lhs.peer.debugDisplayTitle < rhs.peer.debugDisplayTitle
                        })
                    } else {
                        peerList.peers.removeAll()
                        for id in peerIds {
                            guard let maybePeer = peerMap[id], let peer = maybePeer else {
                                continue
                            }
                            peerList.peers.append(PeerList.Peer(
                                peer: peer,
                                isContact: isContactMap[id] ?? false
                            ))
                        }
                        peerList.peers.sort(by: { lhs, rhs in
                            return lhs.peer.debugDisplayTitle < rhs.peer.debugDisplayTitle
                        })
                    }
                    
                    controller?.dismiss()
                    completion(peerList)
                })
            })
            
            return controller
        }
        
        private func openPeerListSetup() {
            guard let component = self.component, let environment = self.environment else {
                return
            }
            let controller = BusinessRecipientListScreenComponent.View.makePeerListSetupScreen(
                context: component.context,
                mode: component.mode,
                initialPeerList: self.peerList,
                completion: { [weak self] peerList in
                    guard let self else {
                        return
                    }
                    self.peerList = peerList
                    self.state?.updated(transition: .immediate)
                }
            )
            environment.controller()?.push(controller)
        }
        
        func update(component: BusinessRecipientListScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
            self.isUpdating = true
            defer {
                self.isUpdating = false
            }
            
            if self.component == nil {
                self.peerList = component.initialData.peerList
            }
            
            let environment = environment[EnvironmentType.self].value
            let themeUpdated = self.environment?.theme !== environment.theme
            self.environment = environment
            
            self.component = component
            self.state = state
            
            let alphaTransition = transition.animation.isImmediate ? transition : .easeInOut(duration: 0.25)
            
            if themeUpdated {
                self.backgroundColor = environment.theme.list.blocksBackgroundColor
            }
            
            let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
            
            let title: String
            switch component.mode {
            case .excludeExceptions, .excludeUsers:
                title = environment.strings.ChatbotSetup_Recipients_ExcludedListTitle
            case .includeExceptions:
                title = environment.strings.ChatbotSetup_Recipients_IncludedListTitle
            }
            
            let navigationTitleSize = self.navigationTitle.update(
                transition: transition,
                component: AnyComponent(MultilineTextComponent(
                    text: .plain(NSAttributedString(string: title, font: Font.semibold(17.0), textColor: environment.theme.rootController.navigationBar.primaryTextColor)),
                    horizontalAlignment: .center
                )),
                environment: {},
                containerSize: CGSize(width: availableSize.width, height: 100.0)
            )
            let navigationTitleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - navigationTitleSize.width) / 2.0), y: environment.statusBarHeight + floor((environment.navigationHeight - environment.statusBarHeight - navigationTitleSize.height) / 2.0)), size: navigationTitleSize)
            if let navigationTitleView = self.navigationTitle.view {
                if navigationTitleView.superview == nil {
                    if let controller = self.environment?.controller(), let navigationBar = controller.navigationBar {
                        navigationBar.view.addSubview(navigationTitleView)
                    }
                }
                transition.setFrame(view: navigationTitleView, frame: navigationTitleFrame)
            }
            
            let bottomContentInset: CGFloat = 24.0
            let sideInset: CGFloat = 16.0 + environment.safeInsets.left
            let sectionSpacing: CGFloat = 32.0
            
            var contentHeight: CGFloat = 0.0
            
            contentHeight += environment.navigationHeight
            contentHeight += 16.0
            
            var excludedSectionItems: [AnyComponentWithIdentity<Empty>] = []
            excludedSectionItems.append(AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent(
                theme: environment.theme,
                title: AnyComponent(VStack([
                    AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
                        text: .plain(NSAttributedString(
                            string: environment.strings.ChatbotSetup_Recipients_AddUsers,
                            font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
                            textColor: environment.theme.list.itemAccentColor
                        )),
                        maximumNumberOfLines: 1
                    ))),
                ], alignment: .left, spacing: 2.0)),
                leftIcon: .custom(AnyComponentWithIdentity(id: 0, component: AnyComponent(BundleIconComponent(
                    name: "Chat List/AddIcon",
                    tintColor: environment.theme.list.itemAccentColor
                )))),
                accessory: nil,
                action: { [weak self] _ in
                    guard let self else {
                        return
                    }
                    self.openPeerListSetup()
                }
            ))))
            for category in self.peerList.categories.sorted(by: { $0.rawValue < $1.rawValue }) {
                let title: String
                let icon: String
                let color: AvatarBackgroundColor
                switch category {
                case .newChats:
                    title = environment.strings.BusinessMessageSetup_Recipients_CategoryNewChats
                    icon = "Chat List/Filters/NewChats"
                    color = .purple
                case .existingChats:
                    title = environment.strings.BusinessMessageSetup_Recipients_CategoryExistingChats
                    icon = "Chat List/Filters/Chats"
                    color = .purple
                case .contacts:
                    title = environment.strings.BusinessMessageSetup_Recipients_CategoryContacts
                    icon = "Chat List/Filters/Contact"
                    color = .blue
                case .nonContacts:
                    title = environment.strings.BusinessMessageSetup_Recipients_CategoryNonContacts
                    icon = "Chat List/Filters/User"
                    color = .yellow
                }
                excludedSectionItems.append(AnyComponentWithIdentity(id: category, component: AnyComponent(PeerListItemComponent(
                    context: component.context,
                    theme: environment.theme,
                    strings: environment.strings,
                    style: .generic,
                    sideInset: 0.0,
                    title: title,
                    avatar: PeerListItemComponent.Avatar(
                        icon: icon,
                        color: color,
                        clipStyle: .roundedRect
                    ),
                    peer: nil,
                    subtitle: nil,
                    subtitleAccessory: .none,
                    presence: nil,
                    selectionState: .none,
                    hasNext: false,
                    action: { peer, _, _ in
                    },
                    inlineActions: PeerListItemComponent.InlineActionsState(
                        actions: [PeerListItemComponent.InlineAction(
                            id: AnyHashable(0),
                            title: environment.strings.Common_Delete,
                            color: .destructive,
                            action: { [weak self] in
                                guard let self else {
                                    return
                                }
                                
                                self.peerList.categories.remove(category)
                                self.state?.updated(transition: .spring(duration: 0.4))
                                
                                if self.peerList.categories.isEmpty && self.peerList.peers.isEmpty {
                                    let _ = self.attemptNavigation(complete: {})
                                    self.environment?.controller()?.dismiss()
                                }
                            }
                        )]
                    )
                ))))
            }
            for peer in self.peerList.peers {
                excludedSectionItems.append(AnyComponentWithIdentity(id: peer.peer.id, component: AnyComponent(PeerListItemComponent(
                    context: component.context,
                    theme: environment.theme,
                    strings: environment.strings,
                    style: .generic,
                    sideInset: 0.0,
                    title: peer.peer.displayTitle(strings: environment.strings, displayOrder: .firstLast),
                    peer: peer.peer,
                    subtitle: peer.isContact ? environment.strings.ChatList_PeerTypeContact : environment.strings.ChatList_PeerTypeNonContactUser,
                    subtitleAccessory: .none,
                    presence: nil,
                    selectionState: .none,
                    hasNext: false,
                    action: { peer, _, _ in
                    },
                    inlineActions: PeerListItemComponent.InlineActionsState(
                        actions: [PeerListItemComponent.InlineAction(
                            id: AnyHashable(0),
                            title: environment.strings.Common_Delete,
                            color: .destructive,
                            action: { [weak self] in
                                guard let self else {
                                    return
                                }
                                self.peerList.peers.removeAll(where: { $0.peer.id == peer.peer.id })
                                self.state?.updated(transition: .spring(duration: 0.4))
                                
                                if self.peerList.categories.isEmpty && self.peerList.peers.isEmpty {
                                    let _ = self.attemptNavigation(complete: {})
                                    self.environment?.controller()?.dismiss()
                                }
                            }
                        )]
                    )
                ))))
            }
            
            let excludedSectionSize = self.excludedSection.update(
                transition: transition,
                component: AnyComponent(ListSectionComponent(
                    theme: environment.theme,
                    header: nil,
                    footer: nil,
                    items: excludedSectionItems
                )),
                environment: {},
                containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
            )
            let excludedSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: excludedSectionSize)
            if let excludedSectionView = self.excludedSection.view {
                if excludedSectionView.superview == nil {
                    self.scrollView.addSubview(excludedSectionView)
                }
                transition.setFrame(view: excludedSectionView, frame: excludedSectionFrame)
            }
            contentHeight += excludedSectionSize.height
            contentHeight += sectionSpacing
            
            let clearSectionSize = self.clearSection.update(
                transition: transition,
                component: AnyComponent(ListSectionComponent(
                    theme: environment.theme,
                    header: nil,
                    footer: nil,
                    items: [AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent(
                        theme: environment.theme,
                        title: AnyComponent(VStack([
                            AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
                                text: .plain(NSAttributedString(
                                    string: environment.strings.ChatbotSetup_Recipients_RemoveAll,
                                    font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
                                    textColor: environment.theme.list.itemDestructiveColor
                                )),
                                maximumNumberOfLines: 1
                            ))),
                        ], alignment: .center, spacing: 2.0, fillWidth: true)),
                        leftIcon: nil,
                        icon: nil,
                        accessory: .none,
                        action: { [weak self] _ in
                            guard let self else {
                                return
                            }
                            self.peerList.categories.removeAll()
                            self.peerList.peers.removeAll()
                            
                            self.state?.updated(transition: .spring(duration: 0.4))
                            
                            if self.peerList.categories.isEmpty && self.peerList.peers.isEmpty {
                                let _ = self.attemptNavigation(complete: {})
                                self.environment?.controller()?.dismiss()
                            }
                        }
                    )))]
                )),
                environment: {},
                containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
            )
            let clearSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: clearSectionSize)
            if let clearSectionView = self.clearSection.view {
                if clearSectionView.superview == nil {
                    self.scrollView.addSubview(clearSectionView)
                }
                transition.setFrame(view: clearSectionView, frame: clearSectionFrame)
                alphaTransition.setAlpha(view: clearSectionView, alpha: (self.peerList.categories.isEmpty && self.peerList.peers.isEmpty) ? 0.0 : 1.0)
            }
            if !self.peerList.categories.isEmpty || !self.peerList.peers.isEmpty {
                contentHeight += clearSectionSize.height
            }
            
            contentHeight += bottomContentInset
            contentHeight += environment.safeInsets.bottom
            
            let previousBounds = self.scrollView.bounds
            
            let contentSize = CGSize(width: availableSize.width, height: contentHeight)
            if self.scrollView.frame != CGRect(origin: CGPoint(), size: availableSize) {
                self.scrollView.frame = CGRect(origin: CGPoint(), size: availableSize)
            }
            if self.scrollView.contentSize != contentSize {
                self.scrollView.contentSize = contentSize
            }
            let scrollInsets = UIEdgeInsets(top: environment.navigationHeight, left: 0.0, bottom: 0.0, right: 0.0)
            if self.scrollView.scrollIndicatorInsets != scrollInsets {
                self.scrollView.scrollIndicatorInsets = scrollInsets
            }
                        
            if !previousBounds.isEmpty, !transition.animation.isImmediate {
                let bounds = self.scrollView.bounds
                if bounds.maxY != previousBounds.maxY {
                    let offsetY = previousBounds.maxY - bounds.maxY
                    transition.animateBoundsOrigin(view: self.scrollView, from: CGPoint(x: 0.0, y: offsetY), to: CGPoint(), additive: true)
                }
            }
            
            self.topOverscrollLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: -3000.0), size: CGSize(width: availableSize.width, height: 3000.0))
            
            self.updateScrolling(transition: transition)
            
            return availableSize
        }
    }
    
    func makeView() -> View {
        return View()
    }
    
    func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
        return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
    }
}

final class BusinessRecipientListScreen: ViewControllerComponentContainer {
    final class InitialData {
        fileprivate let peerList: BusinessRecipientListScreenComponent.PeerList
        
        fileprivate init(
            peerList: BusinessRecipientListScreenComponent.PeerList
        ) {
            self.peerList = peerList
        }
    }
    
    enum Mode {
        case includeExceptions
        case excludeExceptions
        case excludeUsers
    }
    
    private let context: AccountContext
    
    init(context: AccountContext, peerList: BusinessRecipientListScreenComponent.PeerList, mode: Mode, update: @escaping (BusinessRecipientListScreenComponent.PeerList) -> Void) {
        self.context = context
        
        super.init(context: context, component: BusinessRecipientListScreenComponent(
            context: context,
            initialData: InitialData(peerList: peerList),
            mode: mode,
            update: update
        ), navigationBarAppearance: .default, theme: .default, updatedPresentationData: nil)
        
        let presentationData = context.sharedContext.currentPresentationData.with { $0 }
        self.title = ""
        self.navigationItem.backBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
        
        self.scrollToTop = { [weak self] in
            guard let self, let componentView = self.node.hostView.componentView as? BusinessRecipientListScreenComponent.View else {
                return
            }
            componentView.scrollToTop()
        }
        
        self.attemptNavigation = { [weak self] complete in
            guard let self, let componentView = self.node.hostView.componentView as? BusinessRecipientListScreenComponent.View else {
                return true
            }
            
            return componentView.attemptNavigation(complete: complete)
        }
    }
    
    required public init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
    }
    
    @objc private func cancelPressed() {
        self.dismiss()
    }
    
    override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
        super.containerLayoutUpdated(layout, transition: transition)
    }
}