import Foundation
import UIKit
import Display
import AsyncDisplayKit
import TelegramCore
import SwiftSignalKit
import TelegramPresentationData
import ProgressNavigationButtonNode
import AccountContext
import AlertUI
import PresentationDataUtils
import CountrySelectionUI
import PhoneNumberFormat
import CoreTelephony
import MessageUI

public final class ChangePhoneNumberController: ViewController, MFMailComposeViewControllerDelegate {
    private var controllerNode: ChangePhoneNumberControllerNode {
        return self.displayNode as! ChangePhoneNumberControllerNode
    }
    
    private let context: AccountContext
    
    private var currentData: (Int32, String?, String)?
    private let requestDisposable = MetaDisposable()
    
    var inProgress: Bool = false {
        didSet {
            if self.inProgress {
                let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.accentTextColor))
                self.navigationItem.rightBarButtonItem = item
            } else {
                self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
            }
            self.controllerNode.inProgress = self.inProgress
        }
    }
    var loginWithNumber: ((String) -> Void)?
    
    private let hapticFeedback = HapticFeedback()
    
    private var presentationData: PresentationData
    
    public init(context: AccountContext) {
        self.context = context
        self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
        
        super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
        
        self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
        self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
        
        self.title = self.presentationData.strings.ChangePhoneNumberNumber_Title
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
        self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
    }
    
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
        self.requestDisposable.dispose()
    }
    
    func updateData(countryCode: Int32, countryName: String, number: String) {
        if self.currentData == nil || self.currentData! != (countryCode, countryName, number) {
            self.currentData = (countryCode, countryName, number)
            if self.isNodeLoaded {
                self.controllerNode.codeAndNumber = (countryCode, countryName, number)
            }
        }
    }
    
    override public func loadDisplayNode() {
        self.displayNode = ChangePhoneNumberControllerNode(presentationData: self.presentationData)
        self.displayNodeDidLoad()
        self.controllerNode.selectCountryCode = { [weak self] in
            if let strongSelf = self {
                let controller = AuthorizationSequenceCountrySelectionController(strings: strongSelf.presentationData.strings, theme: strongSelf.presentationData.theme)
                controller.completeWithCountryCode = { code, name in
                    if let strongSelf = self {
                        strongSelf.updateData(countryCode: Int32(code), countryName: name, number: strongSelf.controllerNode.codeAndNumber.2)
                        strongSelf.controllerNode.activateInput()
                    }
                }
                strongSelf.controllerNode.view.endEditing(true)
                strongSelf.push(controller)
            }
        }
        
        loadServerCountryCodes(accountManager: self.context.sharedContext.accountManager, engine: self.context.engine, completion: { [weak self] in
            if let strongSelf = self {
                strongSelf.controllerNode.updateCountryCode()
            }
        })
        
        self.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
    }
    
    override public func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        self.controllerNode.activateInput()
    }
    
    override public func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        self.controllerNode.activateInput()
    }
    
    override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
        super.containerLayoutUpdated(layout, transition: transition)
        
        self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: 0.0, transition: transition)
    }
    
    @objc func nextPressed() {
        let (code, _, number) = self.controllerNode.codeAndNumber
        var phoneNumber = number
        if let code = code {
            phoneNumber = "\(code)\(phoneNumber)"
        }
        if !number.isEmpty {
            self.inProgress = true
            self.requestDisposable.set((self.context.engine.accountData.requestChangeAccountPhoneNumberVerification(phoneNumber: self.controllerNode.currentNumber) |> deliverOnMainQueue).start(next: { [weak self] next in
                if let strongSelf = self {
                    strongSelf.inProgress = false
                    (strongSelf.navigationController as? NavigationController)?.pushViewController(changePhoneNumberCodeController(context: strongSelf.context, phoneNumber: strongSelf.controllerNode.currentNumber, codeData: next))
                }
            }, error: { [weak self] error in
                if let strongSelf = self {
                    strongSelf.inProgress = false
                    
                    let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
                
                    let text: String
                    var actions: [TextAlertAction] = []
                    switch error {
                        case .limitExceeded:
                            text = presentationData.strings.Login_CodeFloodError
                            actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
                        case .invalidPhoneNumber:
                            text = presentationData.strings.Login_InvalidPhoneError
                            actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
                        case .phoneNumberOccupied:
                            text = presentationData.strings.ChangePhone_ErrorOccupied(formatPhoneNumber(phoneNumber)).string
                            actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
                        case .phoneBanned:
                            text = presentationData.strings.Login_PhoneBannedError
                            actions.append(TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
                            actions.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Login_PhoneNumberHelp, action: { [weak self] in
                                guard let strongSelf = self else {
                                    return
                                }
                                let formattedNumber = formatPhoneNumber(number)
                                let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
                                let systemVersion = UIDevice.current.systemVersion
                                let locale = Locale.current.identifier
                                let carrier = CTCarrier()
                                let mnc = carrier.mobileNetworkCode ?? "none"
                                
                                strongSelf.presentEmailComposeController(address: "login@stel.com", subject: presentationData.strings.Login_PhoneBannedEmailSubject(formattedNumber).string, body: presentationData.strings.Login_PhoneBannedEmailBody(formattedNumber, appVersion, systemVersion, locale, mnc).string)
                            }))
                        case .generic:
                            text = presentationData.strings.Login_UnknownError
                            actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
                    }
                    
                    strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: actions), in: .window(.root))
                }
            }))
        } else {
            self.hapticFeedback.error()
            self.controllerNode.animateError()
        }
    }
    
    private func presentEmailComposeController(address: String, subject: String, body: String) {
        if MFMailComposeViewController.canSendMail() {
            let composeController = MFMailComposeViewController()
            composeController.setToRecipients([address])
            composeController.setSubject(subject)
            composeController.setMessageBody(body, isHTML: false)
            composeController.mailComposeDelegate = self
            
            self.view.window?.rootViewController?.present(composeController, animated: true, completion: nil)
        } else {
            self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Login_EmailNotConfiguredError, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
        }
    }
    
    public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
        controller.dismiss(animated: true, completion: nil)
    }
}