import Foundation
import AsyncDisplayKit
import Display

private let passwordFont = Font.regular(16.0)
private let buttonFont = Font.regular(17.0)

final class SecureIdAuthPasswordOptionContentNode: ASDisplayNode, SecureIdAuthContentNode, UITextFieldDelegate {
    private let checkPassword: (String) -> Void
    private let passwordHelp: () -> Void
    
    private let inputContainer: ASDisplayNode
    private let titleNode: ImmediateTextNode
    private let inputBackground: ASImageNode
    private let inputField: TextFieldNode
    private var clearOnce: Bool = false
    private let inputButtonNode: HighlightableButtonNode
    private let inputActivityNode: ActivityIndicator
    
    private let buttonNode: HighlightableButtonNode
    private let buttonBackground: ASImageNode
    private let buttonLabel: ImmediateTextNode
    
    private var validLayout: CGFloat?
    
    private var isChecking = false
    
    private let hapticFeedback = HapticFeedback()
    
    init(theme: PresentationTheme, strings: PresentationStrings, hint: String, checkPassword: @escaping (String) -> Void, passwordHelp: @escaping () -> Void) {
        self.checkPassword = checkPassword
        self.passwordHelp = passwordHelp
        
        self.inputContainer = ASDisplayNode()
        self.inputBackground = ASImageNode()
        self.inputBackground.isLayerBacked = true
        self.inputBackground.displaysAsynchronously = false
        self.inputBackground.displayWithoutProcessing = true
        self.titleNode = ImmediateTextNode()
        self.titleNode.attributedText = NSAttributedString(string: strings.Passport_PasswordHelp, font: Font.regular(14.0), textColor: theme.list.freeTextColor)
        self.titleNode.maximumNumberOfLines = 0
        self.titleNode.textAlignment = .center
        self.inputField = TextFieldNode()
        
        self.inputButtonNode = HighlightableButtonNode()
        self.inputActivityNode = ActivityIndicator(type: .custom(theme.list.itemAccentColor, 18.0, 1.5, false))
       
        if let image = generateTintedImage(image: UIImage(bundleImageName: "Secure ID/PasswordHelpIcon"), color: theme.list.freeInputField.controlColor) {
            self.inputButtonNode.setImage(image, for: [])
            self.inputButtonNode.frame = CGRect(origin: CGPoint(), size: image.size)
        }
        
        self.inputBackground.image = generateStretchableFilledCircleImage(radius: 10.0, color: theme.list.freeInputField.backgroundColor)
        
        self.inputField.textField.isSecureTextEntry = true
        self.inputField.textField.font = passwordFont
        self.inputField.textField.textColor = theme.list.freeInputField.primaryColor
        self.inputField.textField.attributedPlaceholder = NSAttributedString(string: hint.isEmpty ? strings.LoginPassword_PasswordPlaceholder : hint, font: passwordFont, textColor: theme.list.freeInputField.placeholderColor)
        self.inputField.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
        
        self.buttonNode = HighlightableButtonNode()
        
        self.buttonBackground = ASImageNode()
        self.buttonBackground.isLayerBacked = true
        self.buttonBackground.displaysAsynchronously = false
        self.buttonBackground.displayWithoutProcessing = true
        self.buttonBackground.image = generateStretchableFilledCircleImage(radius: 10.0, color: theme.list.itemCheckColors.fillColor)
        self.buttonNode.addSubnode(self.buttonBackground)
        
        self.buttonLabel = ImmediateTextNode()
        self.buttonLabel.attributedText = NSAttributedString(string: strings.Common_Next, font: buttonFont, textColor: theme.list.itemCheckColors.foregroundColor)
        self.buttonNode.addSubnode(self.buttonLabel)
        
        super.init()
        
        self.inputContainer.addSubnode(self.titleNode)
        self.inputContainer.addSubnode(self.inputBackground)
        self.inputContainer.addSubnode(self.inputField)
        self.inputContainer.addSubnode(self.inputButtonNode)
        self.inputContainer.addSubnode(self.inputActivityNode)
        self.inputContainer.addSubnode(self.buttonNode)
        
        self.addSubnode(self.inputContainer)
        
        self.buttonNode.highligthedChanged = { [weak self] highlighted in
            if let strongSelf = self {
                if highlighted {
                    strongSelf.buttonBackground.layer.removeAnimation(forKey: "opacity")
                    strongSelf.buttonBackground.alpha = 0.55
                } else {
                    strongSelf.buttonBackground.alpha = 1.0
                    strongSelf.buttonBackground.layer.animateAlpha(from: 0.55, to: 1.0, duration: 0.2)
                }
            }
        }
        
        self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
        
        self.inputField.textField.delegate = self
        
        self.inputButtonNode.hitTestSlop = UIEdgeInsets(top: -4.0, left: -4.0, bottom: -4.0, right: -4.0)
        self.inputButtonNode.addTarget(self, action: #selector(self.inputButtonPressed), forControlEvents: .touchUpInside)
        self.inputActivityNode.isHidden = true
    }
    
    func updateLayout(width: CGFloat, transition: ContainedViewLayoutTransition) -> SecureIdAuthContentLayout {
        let transition = self.validLayout == nil ? .immediate : transition
        self.validLayout = width
        
        let inputWidth = min(270.0, width - 30.0)
        
        let labelSize = self.buttonLabel.updateLayout(CGSize(width: width - 20.0, height: 100.0))
        let buttonSize = CGSize(width: max(labelSize.width + 30.0, 100.0), height: 36.0)
        
        let titleSpacing: CGFloat = 15.0
        
        let titleSize = self.titleNode.updateLayout(CGSize(width: inputWidth, height: CGFloat.greatestFiniteMagnitude))
        
        let buttonSpacing: CGFloat = 16.0
        
        let inputFrame = CGRect(origin: CGPoint(x: floor((width - inputWidth) / 2.0), y: titleSize.height + titleSpacing), size: CGSize(width: inputWidth, height: 32.0))
        
        let inputContainerFrame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: titleSize.height + titleSpacing + inputFrame.height + buttonSpacing + buttonSize.height))
        
        let titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: 0.0), size: titleSize)
        
        transition.updateFrame(node: self.inputContainer, frame: inputContainerFrame)
        transition.updateFrame(node: self.titleNode, frame: titleFrame)
        transition.updateFrame(node: self.inputBackground, frame: inputFrame)
        var inputFieldFrame = inputFrame.insetBy(dx: 6.0, dy: 0.0)
        inputFieldFrame.size.width -= 16.0
        transition.updateFrame(node: self.inputField, frame: inputFieldFrame)
        
        transition.updateFrame(node: self.inputButtonNode, frame: CGRect(origin: CGPoint(x: inputFrame.maxX - self.inputButtonNode.bounds.size.width - 6.0, y: inputFrame.minY + floor((inputFrame.height - self.inputButtonNode.bounds.size.height) / 2.0)), size: self.inputButtonNode.bounds.size))
        
        let activitySize = CGSize(width: 18.0, height: 18.0)
        transition.updateFrame(node: self.inputActivityNode, frame: CGRect(origin: CGPoint(x: inputFrame.maxX - activitySize.width - 6.0, y: inputFrame.minY + floor((inputFrame.height - activitySize.height) / 2.0)), size: activitySize))
        
        let buttonBounds = CGRect(origin: CGPoint(), size: buttonSize)
        transition.updateFrame(node: self.buttonNode, frame: buttonBounds.offsetBy(dx: floor((width - buttonSize.width) / 2.0), dy: inputFrame.maxY + buttonSpacing))
        transition.updateFrame(node: self.buttonBackground, frame: buttonBounds)
        transition.updateFrame(node: self.buttonLabel, frame: CGRect(origin: CGPoint(x: floor((buttonSize.width - labelSize.width) / 2.0), y: floor((buttonSize.height - labelSize.height) / 2.0)), size: buttonSize))
        
        return SecureIdAuthContentLayout(height: inputContainerFrame.size.height, centerOffset: floor((inputContainerFrame.size.height) / 2.0))
    }
    
    func animateIn() {
        self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
    }
    
    func animateOut(completion: @escaping () -> Void) {
        self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
            completion()
        })
    }
    
    func didAppear() {
        self.inputField.textField.becomeFirstResponder()
    }
    
    func willDisappear() {
        self.inputField.textField.resignFirstResponder()
    }
    
    @objc private func buttonPressed() {
        if self.isChecking {
            return
        }
        
        if self.inputField.textField.text?.isEmpty ?? true {
            self.inputField.layer.addShakeAnimation()
            self.inputBackground.layer.addShakeAnimation()
            self.hapticFeedback.error()
        } else {
            self.checkPassword(self.inputField.textField.text ?? "")
        }
    }
    
    @objc private func inputButtonPressed() {
        self.passwordHelp()
    }
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if self.isChecking {
            return false
        }
        
        if self.clearOnce {
            self.clearOnce = false
            if range.length > string.count {
                textField.text = ""
                return false
            }
        }
        return true
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if !self.isChecking {
            self.buttonPressed()
        }
        return false
    }
    
    func updateIsChecking(_ isChecking: Bool) {
        self.isChecking = isChecking
        self.inputField.alpha = isChecking ? 0.5 : 1.0
        self.inputActivityNode.isHidden = !isChecking
        self.inputButtonNode.isHidden = isChecking
    }
    
    func updateIsInvalid() {
        self.clearOnce = true
    }
}