import Foundation
import UIKit
import Display
import AsyncDisplayKit
import SwiftSignalKit
import Postbox
import TelegramCore
import SyncCore
import TelegramPresentationData
import TextFormat
import ProgressNavigationButtonNode
import AccountContext
import AlertUI
import PresentationDataUtils
import PasswordSetupUI

public enum SecureIdRequestResult: String {
    case success = "success"
    case cancel = "cancel"
    case error = "error"
}

public func secureIdCallbackUrl(with baseUrl: String, peerId: PeerId, result: SecureIdRequestResult, parameters: [String : String]) -> String {
    var query = (parameters.compactMap({ (key, value) -> String in
        return "\(key)=\(value)"
    }) as Array).joined(separator: "&")
    
    if !query.isEmpty {
        query = "?" + query
    }
    
    let url: String
    if baseUrl.hasPrefix("tgbot") {
        url = "tgbot\(peerId.id)://passport/" + result.rawValue + query
    } else {
        url = baseUrl + (baseUrl.range(of: "?") != nil ? "&" : "?") + "tg_passport=" + result.rawValue + query
    }
    return url
}

final class SecureIdAuthControllerInteraction {
    let updateState: ((SecureIdAuthControllerState) -> SecureIdAuthControllerState) -> Void
    let present: (ViewController, Any?) -> Void
    let push: (ViewController) -> Void
    let checkPassword: (String) -> Void
    let openPasswordHelp: () -> Void
    let setupPassword: () -> Void
    let grant: () -> Void
    let openUrl: (String) -> Void
    let openMention: (TelegramPeerMention) -> Void
    let deleteAll: () -> Void
    
    fileprivate init(updateState: @escaping ((SecureIdAuthControllerState) -> SecureIdAuthControllerState) -> Void, present: @escaping (ViewController, Any?) -> Void, push: @escaping (ViewController) -> Void, checkPassword: @escaping (String) -> Void, openPasswordHelp: @escaping () -> Void, setupPassword: @escaping () -> Void, grant: @escaping () -> Void, openUrl: @escaping (String) -> Void, openMention: @escaping (TelegramPeerMention) -> Void, deleteAll: @escaping () -> Void) {
        self.updateState = updateState
        self.present = present
        self.push = push
        self.checkPassword = checkPassword
        self.openPasswordHelp = openPasswordHelp
        self.setupPassword = setupPassword
        self.grant = grant
        self.openUrl = openUrl
        self.openMention = openMention
        self.deleteAll = deleteAll
    }
}

public enum SecureIdAuthControllerMode {
    case form(peerId: PeerId, scope: String, publicKey: String, callbackUrl: String, opaquePayload: Data, opaqueNonce: Data)
    case list
}

public final class SecureIdAuthController: ViewController, StandalonePresentableController {
    private var controllerNode: SecureIdAuthControllerNode {
        return self.displayNode as! SecureIdAuthControllerNode
    }
    
    private let context: AccountContext
    private var presentationData: PresentationData
    private let mode: SecureIdAuthControllerMode
    
    private var didPlayPresentationAnimation = false
    
    private let challengeDisposable = MetaDisposable()
    private let authenthicateDisposable = MetaDisposable()
    private var formDisposable: Disposable?
    private let deleteDisposable = MetaDisposable()
    private let recoveryDisposable = MetaDisposable()
    
    private var state: SecureIdAuthControllerState
    
    private let hapticFeedback = HapticFeedback()
    
    public init(context: AccountContext, mode: SecureIdAuthControllerMode) {
        self.context = context
        self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
        
        self.mode = mode
        
        switch mode {
            case .form:
                self.state = .form(SecureIdAuthControllerFormState(twoStepEmail: nil, encryptedFormData: nil, formData: nil, verificationState: nil, removingValues: false))
            case .list:
                self.state = .list(SecureIdAuthControllerListState(accountPeer: nil, twoStepEmail: nil, verificationState: nil, encryptedValues: nil, primaryLanguageByCountry: [:], values: nil, removingValues: false))
        }
        
        super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
        
        if case .list = mode {
            self.navigationPresentation = .modal
        }
        
        self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
        
        self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
        
        self.title = self.presentationData.strings.Passport_Title
        switch mode {
            case .form:
                self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
            case .list:
                self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.cancelPressed))
        }
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationInfoIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.infoPressed))
        
        self.challengeDisposable.set((twoStepAuthData(context.account.network)
        |> deliverOnMainQueue).start(next: { [weak self] data in
            if let strongSelf = self {
                let storedPassword = context.getStoredSecureIdPassword()
                if data.currentPasswordDerivation != nil, let storedPassword = storedPassword {
                    strongSelf.authenthicateDisposable.set((accessSecureId(network: strongSelf.context.account.network, password: storedPassword)
                    |> deliverOnMainQueue).start(next: { context in
                        guard let strongSelf = self, strongSelf.state.verificationState == nil else {
                            return
                        }
                        
                        strongSelf.updateState(animated: true, { state in
                            var state = state
                            state.verificationState = .verified(context.context)
                            state.twoStepEmail = !context.settings.email.isEmpty ? context.settings.email : nil
                            switch state {
                                case var .form(form):
                                    form.formData = form.encryptedFormData.flatMap({ decryptedSecureIdForm(context: context.context, form: $0.form) })
                                    state = .form(form)
                                case var .list(list):
                                    list.values = list.encryptedValues.flatMap({ decryptedAllSecureIdValues(context: context.context, encryptedValues: $0) })
                                    state = .list(list)
                            }
                            return state
                        })
                    }, error: { [weak self] error in
                        guard let strongSelf = self else {
                            return
                        }
                        if strongSelf.state.verificationState == nil {
                            strongSelf.updateState(animated: true, { state in
                                var state = state
                                state.verificationState = .passwordChallenge(hint: data.currentHint ?? "", state: .none, hasRecoveryEmail: data.hasRecovery)
                                return state
                            })
                        }
                    }))
                } else {
                    strongSelf.updateState { state in
                        var state = state
                        if data.currentPasswordDerivation != nil {
                            state.verificationState = .passwordChallenge(hint: data.currentHint ?? "", state: .none, hasRecoveryEmail: data.hasRecovery)
                        } else if let unconfirmedEmailPattern = data.unconfirmedEmailPattern {
                            state.verificationState = .noChallenge(.awaitingConfirmation(password: nil, emailPattern: unconfirmedEmailPattern, codeLength: nil))
                        } else {
                            state.verificationState = .noChallenge(.notSet)
                        }
                        return state
                    }
                }
            }
        }))
        
        let handleError: (Any, String?, PeerId?) -> Void = { [weak self] error, callbackUrl, peerId in
            if let strongSelf = self {
                var passError: String?
                var appUpdateRequired = false
                switch error {
                    case let error as RequestSecureIdFormError:
                        if case let .serverError(error) = error, ["BOT_INVALID", "PUBLIC_KEY_REQUIRED", "PUBLIC_KEY_INVALID", "SCOPE_EMPTY", "PAYLOAD_EMPTY", "NONCE_EMPTY"].contains(error) {
                            passError = error
                        } else if case .versionOutdated = error {
                            appUpdateRequired = true
                        }
                        break
                    case let error as GetAllSecureIdValuesError:
                        if case .versionOutdated = error {
                            appUpdateRequired = true
                        }
                        break
                    default:
                        break
                }
                
                if appUpdateRequired {
                    let errorText = strongSelf.presentationData.strings.Passport_UpdateRequiredError
                    strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Application_Update, action: {
                        context.sharedContext.applicationBindings.openAppStorePage()
                    })]), in: .window(.root))
                } else if let callbackUrl = callbackUrl, let peerId = peerId {
                    let errorText = strongSelf.presentationData.strings.Login_UnknownError
                    strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
                        if let error = passError {
                            strongSelf.openUrl(secureIdCallbackUrl(with: callbackUrl, peerId: peerId, result: .error, parameters: ["error": error]))
                        }
                    })]), in: .window(.root))
                }
                strongSelf.dismiss()
            }
        }
        
        switch self.mode {
            case let .form(peerId, scope, publicKey, callbackUrl, _, _):
                self.formDisposable = (combineLatest(requestSecureIdForm(postbox: context.account.postbox, network: context.account.network, peerId: peerId, scope: scope, publicKey: publicKey), secureIdConfiguration(postbox: context.account.postbox, network: context.account.network) |> castError(RequestSecureIdFormError.self))
                |> mapToSignal { form, configuration -> Signal<SecureIdEncryptedFormData, RequestSecureIdFormError> in
                    return context.account.postbox.transaction { transaction -> Signal<SecureIdEncryptedFormData, RequestSecureIdFormError> in
                        guard let accountPeer = transaction.getPeer(context.account.peerId), let servicePeer = transaction.getPeer(form.peerId) else {
                            return .fail(.generic)
                        }
                        
                        let primaryLanguageByCountry = configuration.nativeLanguageByCountry
                        return .single(SecureIdEncryptedFormData(form: form, primaryLanguageByCountry: primaryLanguageByCountry, accountPeer: accountPeer, servicePeer: servicePeer))
                    }
                    |> mapError { _ in return RequestSecureIdFormError.generic }
                    |> switchToLatest
                }
                |> deliverOnMainQueue).start(next: { [weak self] formData in
                    if let strongSelf = self {
                        strongSelf.updateState { state in
                            var state = state
                            switch state {
                                case var .form(form):
                                    form.encryptedFormData = formData
                                    state = .form(form)
                                case .list:
                                    break
                            }
                            return state
                        }
                    }
                }, error: { error in
                    handleError(error, callbackUrl, peerId)
                })
            case .list:
                self.formDisposable = (combineLatest(getAllSecureIdValues(network: self.context.account.network), secureIdConfiguration(postbox: context.account.postbox, network: context.account.network) |> castError(GetAllSecureIdValuesError.self), context.account.postbox.transaction { transaction -> Signal<Peer, GetAllSecureIdValuesError> in
                    guard let accountPeer = transaction.getPeer(context.account.peerId) else {
                        return .fail(.generic)
                    }
                    
                    return .single(accountPeer)
                    }
                    |> mapError { _ in return GetAllSecureIdValuesError.generic }
                    |> switchToLatest)
                |> deliverOnMainQueue).start(next: { [weak self] values, configuration, accountPeer in
                    if let strongSelf = self {
                        strongSelf.updateState { state in
                            let state = state
                            let primaryLanguageByCountry = configuration.nativeLanguageByCountry
                            
                            switch state {
                                case .form:
                                    break
                                case var .list(list):
                                    list.accountPeer = accountPeer
                                    list.primaryLanguageByCountry = primaryLanguageByCountry
                                    list.encryptedValues = values
                                    return .list(list)
                            }
                            return state
                        }
                    }
                }, error: { error in
                    handleError(error, nil, nil)
                })
        }
    }
    
    required public init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
        self.challengeDisposable.dispose()
        self.authenthicateDisposable.dispose()
        self.formDisposable?.dispose()
        self.deleteDisposable.dispose()
        self.recoveryDisposable.dispose()
    }
    
    override public func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        if case .form = self.mode, !self.didPlayPresentationAnimation {
            self.didPlayPresentationAnimation = true
            self.controllerNode.animateIn()
        }
    }
    
    override public func loadDisplayNode() {
        let interaction = SecureIdAuthControllerInteraction(updateState: { [weak self] f in
            self?.updateState(f)
        }, present: { [weak self] c, a in
            self?.present(c, in: .window(.root), with: a)
        }, push: { [weak self] c in
            self?.push(c)
        }, checkPassword: { [weak self] password in
            self?.checkPassword(password: password, inBackground: false, completion: {})
        }, openPasswordHelp: { [weak self] in
            self?.openPasswordHelp()
        }, setupPassword: { [weak self] in
            self?.setupPassword()
        }, grant: { [weak self] in
            self?.grantAccess()
        }, openUrl: { [weak self] url in
            if let strongSelf = self {
                strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: url, forceExternal: false, presentationData: strongSelf.presentationData, navigationController: strongSelf.navigationController as? NavigationController, dismissInput: {
                    self?.view.endEditing(true)
                })
            }
        }, openMention: { [weak self] mention in
            guard let strongSelf = self else {
                return
            }
            let _ = (strongSelf.context.account.postbox.loadedPeerWithId(mention.peerId)
            |> deliverOnMainQueue).start(next: { peer in
                guard let strongSelf = self else {
                    return
                }
                if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) {
                    (strongSelf.navigationController as? NavigationController)?.pushViewController(infoController)
                }
            })
        }, deleteAll: { [weak self] in
            guard let strongSelf = self, case let .list(list) = strongSelf.state, let values = list.values else {
                return
            }
            
            let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: strongSelf.presentationData.theme.rootController.navigationBar.controlColor))
            strongSelf.navigationItem.rightBarButtonItem = item
            strongSelf.deleteDisposable.set((deleteSecureIdValues(network: strongSelf.context.account.network, keys: Set(values.map({ $0.value.key })))
            |> deliverOnMainQueue).start(completed: {
                guard let strongSelf = self else {
                    return
                }
                strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationInfoIcon(strongSelf.presentationData.theme), style: .plain, target: self, action: #selector(strongSelf.infoPressed))
                strongSelf.updateState { state in
                    if case var .list(list) = state {
                        list.values = []
                        return .list(list)
                    }
                    return state
                }
            }))
        })
        
        self.displayNode = SecureIdAuthControllerNode(context: self.context, presentationData: presentationData, requestLayout: { [weak self] transition in
            self?.requestLayout(transition: transition)
        }, interaction: interaction)
        self.controllerNode.updateState(self.state, transition: .immediate)
    }
    
    override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
        super.containerLayoutUpdated(layout, transition: transition)
        
        self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
    }
    
    override public func dismiss(completion: (() -> Void)? = nil) {
        if case .form = self.mode {
            self.controllerNode.animateOut(completion: { [weak self] in
                self?.presentingViewController?.dismiss(animated: false, completion: nil)
                completion?()
            })
        } else {
            super.dismiss(completion: completion)
        }
    }
    
    private func updateState(animated: Bool = true, _ f: (SecureIdAuthControllerState) -> SecureIdAuthControllerState) {
        let state = f(self.state)
        if state != self.state {
            var previousHadProgress = false
            if let verificationState = self.state.verificationState, case .passwordChallenge(_, .checking, _) = verificationState {
                previousHadProgress = true
            }
            if self.state.removingValues {
                previousHadProgress = true
            }
            var updatedHasProgress = false
            if let verificationState = state.verificationState, case .passwordChallenge(_, .checking, _) = verificationState {
                updatedHasProgress = true
            }
            if state.removingValues {
                updatedHasProgress = true
            }
            
            self.state = state
            if self.isNodeLoaded {
                self.controllerNode.updateState(self.state, transition: animated ? .animated(duration: 0.3, curve: .spring) : .immediate)
            }
            
            if previousHadProgress != updatedHasProgress {
                if updatedHasProgress {
                    let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.controlColor))
                    self.navigationItem.rightBarButtonItem = item
                } else {
                    self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationInfoIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.infoPressed))
                }
            }
        }
    }
    
    private func openUrl(_ url: String) {
        self.context.sharedContext.openExternalUrl(context: self.context, urlContext: .generic, url: url, forceExternal: true, presentationData: self.presentationData, navigationController: nil, dismissInput: { [weak self] in
            self?.view.endEditing(true)
        })
    }
    
    @objc private func cancelPressed() {
        self.dismiss()
        
        if case let .form(reqForm) = self.mode {
            self.openUrl(secureIdCallbackUrl(with: reqForm.callbackUrl, peerId: reqForm.peerId, result: .cancel, parameters: [:]))
        }
    }
    
    @objc private func checkPassword(password: String, inBackground: Bool, completion: @escaping () -> Void) {
        if let verificationState = self.state.verificationState, case let .passwordChallenge(hint, challengeState, hasRecoveryEmail) = verificationState {
            switch challengeState {
                case .none, .invalid:
                    break
                case .checking:
                    return
            }
            self.updateState(animated: !inBackground, { state in
                var state = state
                state.verificationState = .passwordChallenge(hint: hint, state: .checking, hasRecoveryEmail: hasRecoveryEmail)
                return state
            })
            self.challengeDisposable.set((accessSecureId(network: self.context.account.network, password: password)
            |> deliverOnMainQueue).start(next: { [weak self] context in
                guard let strongSelf = self, let verificationState = strongSelf.state.verificationState, case .passwordChallenge(_, .checking, _) = verificationState else {
                    return
                }
                strongSelf.context.storeSecureIdPassword(password: password)
                strongSelf.updateState(animated: !inBackground, { state in
                    var state = state
                    state.verificationState = .verified(context.context)
                    state.twoStepEmail = !context.settings.email.isEmpty ? context.settings.email : nil
                    switch state {
                        case var .form(form):
                            form.formData = form.encryptedFormData.flatMap({ decryptedSecureIdForm(context: context.context, form: $0.form) })
                            state = .form(form)
                        case var .list(list):
                            list.values = list.encryptedValues.flatMap({ decryptedAllSecureIdValues(context: context.context, encryptedValues: $0) })
                            state = .list(list)
                    }
                    return state
                })
                completion()
            }, error: { [weak self] error in
                guard let strongSelf = self else {
                    return
                }
                let errorText: String
                switch error {
                    case let .passwordError(passwordError):
                        switch passwordError {
                            case .invalidPassword:
                                errorText = strongSelf.presentationData.strings.LoginPassword_InvalidPasswordError
                            case .limitExceeded:
                                errorText = strongSelf.presentationData.strings.LoginPassword_FloodError
                            case .generic:
                                errorText = strongSelf.presentationData.strings.Login_UnknownError
                        }
                    case .generic:
                        errorText = strongSelf.presentationData.strings.Login_UnknownError
                    case .secretPasswordMismatch:
                        errorText = strongSelf.presentationData.strings.Login_UnknownError
                }
                strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
                
                if let verificationState = strongSelf.state.verificationState, case let .passwordChallenge(hint, .checking, hasRecoveryEmail) = verificationState {
                    strongSelf.updateState(animated: !inBackground, { state in
                        var state = state
                        state.verificationState = .passwordChallenge(hint: hint, state: .invalid, hasRecoveryEmail: hasRecoveryEmail)
                        return state
                    })
                }
                completion()
            }))
        }
    }
    
    private func openPasswordHelp() {
        guard let verificationState = self.state.verificationState, case let .passwordChallenge(passwordChallenge) = verificationState else {
            return
        }
        switch passwordChallenge.state {
            case .checking:
                return
            case .none, .invalid:
                break
        }
        
        if passwordChallenge.hasRecoveryEmail {
            self.present(textAlertController(context: self.context, title: self.presentationData.strings.Passport_ForgottenPassword, text: self.presentationData.strings.Passport_PasswordReset, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Login_ResetAccountProtected_Reset, action: { [weak self] in
                guard let strongSelf = self else {
                    return
                }
                strongSelf.recoveryDisposable.set((requestTwoStepVerificationPasswordRecoveryCode(network: strongSelf.context.account.network)
                |> deliverOnMainQueue).start(next: { emailPattern in
                    guard let strongSelf = self else {
                        return
                    }
                    var completionImpl: (() -> Void)?
                    let controller = resetPasswordController(context: strongSelf.context, emailPattern: emailPattern, completion: {
                        completionImpl?()
                    })
                    completionImpl = { [weak controller] in
                        guard let strongSelf = self else {
                            return
                        }
                        strongSelf.updateState(animated: false, { state in
                            var state = state
                            state.verificationState = .noChallenge(.notSet)
                            return state
                        })
                        controller?.view.endEditing(true)
                        controller?.dismiss()
                        strongSelf.setupPassword()
                    }
                    strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
                }))
            })]), in: .window(.root))
        } else {
            self.present(textAlertController(context: self.context, title: nil, text: self.presentationData.strings.TwoStepAuth_RecoveryUnavailable, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
        }
    }
    
    private func setupPassword() {
        guard let verificationState = self.state.verificationState, case let .noChallenge(noChallengeState) = verificationState else {
            return
        }
        let initialState: SetupTwoStepVerificationInitialState
        switch noChallengeState {
            case .notSet:
                initialState = .createPassword
            case let .awaitingConfirmation(password, emailPattern, codeLength):
                initialState = .confirmEmail(password: password, hasSecureValues: false, pattern: emailPattern, codeLength: codeLength)
        }
        let controller = SetupTwoStepVerificationController(context: self.context, initialState: initialState, stateUpdated: { [weak self] update, shouldDismiss, controller in
            guard let strongSelf = self else {
                return
            }
            switch update {
                case .noPassword:
                    strongSelf.updateState(animated: false, { state in
                        var state = state
                        if let verificationState = state.verificationState, case .noChallenge = verificationState {
                            state.verificationState = .noChallenge(.notSet)
                        }
                        return state
                    })
                    if shouldDismiss {
                        controller.dismiss()
                    }
                case let .awaitingEmailConfirmation(password, pattern, codeLength):
                    strongSelf.updateState(animated: false, { state in
                        var state = state
                        if let verificationState = state.verificationState, case .noChallenge = verificationState {
                            state.verificationState = .noChallenge(.awaitingConfirmation(password: password, emailPattern: pattern, codeLength: codeLength))
                        }
                        return state
                    })
                    if shouldDismiss {
                        controller.dismiss()
                    }
                case let .passwordSet(password, hasRecoveryEmail, _):
                    strongSelf.updateState(animated: false, { state in
                        var state = state
                        state.verificationState = .passwordChallenge(hint: "", state: .none, hasRecoveryEmail: hasRecoveryEmail)
                        return state
                    })
                    if let password = password {
                        strongSelf.checkPassword(password: password, inBackground: true, completion: { [weak controller] in
                            controller?.dismiss()
                        })
                    } else if shouldDismiss {
                        controller.dismiss()
                    }
            }
        })
        self.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
        
        /*var completionImpl: ((String, String, Bool) -> Void)?
        let state: CreatePasswordState
        if let emailPattern = emailPattern {
            state = .pendingVerification(emailPattern: emailPattern)
        } else {
            state = .setup(currentPassword: nil)
        }
        let controller = createPasswordController(account: self.account, context: .secureId, state: state, completion: { password, hint, hasRecoveryEmail in
            completionImpl?(password, hint, hasRecoveryEmail)
        }, updatePasswordEmailConfirmation: { [weak self] pattern in
            guard let strongSelf = self else {
                return
            }
            strongSelf.updateState(animated: false, { state in
                var state = state
                if let verificationState = state.verificationState, case .noChallenge = verificationState {
                    state.verificationState = .noChallenge(pattern?.1)
                }
                return state
            })
        })
        completionImpl = { [weak self, weak controller] password, hint, hasRecoveryEmail in
            guard let strongSelf = self else {
                controller?.dismiss()
                return
            }
            strongSelf.updateState(animated: false, { state in
                var state = state
                state.verificationState = .passwordChallenge(hint: hint, state: .none, hasRecoveryEmail: hasRecoveryEmail)
                return state
            })
            strongSelf.checkPassword(password: password, inBackground: true, completion: {
                controller?.view.endEditing(true)
                controller?.dismiss()
            })
        }
        self.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))*/
    }
    
    @objc private func grantAccess() {
        switch self.state {
            case let .form(form):
                if case let .form(reqForm) = self.mode, let encryptedFormData = form.encryptedFormData, let formData = form.formData {
                    let values = parseRequestedFormFields(formData.requestedFields, values: formData.values, primaryLanguageByCountry: encryptedFormData.primaryLanguageByCountry).map({ $0.1 }).flatMap({ $0 })
                    
                    let _ = (grantSecureIdAccess(network: self.context.account.network, peerId: encryptedFormData.servicePeer.id, publicKey: reqForm.publicKey, scope: reqForm.scope, opaquePayload: reqForm.opaquePayload, opaqueNonce: reqForm.opaqueNonce, values: values, requestedFields: formData.requestedFields)
                    |> deliverOnMainQueue).start(completed: { [weak self] in
                        self?.dismiss()
                        self?.openUrl(secureIdCallbackUrl(with: reqForm.callbackUrl, peerId: reqForm.peerId, result: .success, parameters: [:]))
                    })
                }
            case .list:
                break
        }
    }
    
    @objc private func infoPressed() {
        self.present(textAlertController(context: self.context, title: self.presentationData.strings.Passport_InfoTitle, text: self.presentationData.strings.Passport_InfoText.replacingOccurrences(of: "**", with: ""), actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {}), TextAlertAction(type: .genericAction, title: self.presentationData.strings.Passport_InfoLearnMore, action: { [weak self] in
            guard let strongSelf = self else {
                return
            }
            strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: strongSelf.presentationData.strings.Passport_InfoFAQ_URL, forceExternal: false, presentationData: strongSelf.presentationData, navigationController: strongSelf.navigationController as? NavigationController, dismissInput: {
                self?.view.endEditing(true)
            })
        })]), in: .window(.root))
    }
}
