import UIKit

protocol PNKeyboardDelegate: class {
    func returnClicked()
}

protocol PNButtonDelegate: class {
    func buttonTapped(_ button: PNButton)
}

enum PNButtonType {
    case symbol(String)
    case backspace
    case done
}

class PNButton: UIButton {
    private(set) var type: PNButtonType
    private var timer: Timer?
    private var waitCount = 0
    private var rectLayer = CAShapeLayer()
    private var bgColor = UIColor(named: "KeyBackground")
    
    weak var delegate: PNButtonDelegate?
    
    init(letter: Character) {
        self.type = .symbol(String(letter))
        super.init(frame: .zero)
        self.setup()
        self.titleLabel?.font = UIFont(name: "RoadNumbers", size: 36)
        let title = String(Constants.pnLettersMap[letter] ?? letter)
        self.setTitle(title, for: .normal)
        self.setTitleColor(.label, for: .normal)
    }
    
    init(digit: Int) {
        self.type = .symbol(String(digit))
        super.init(frame: .zero)
        self.setup()
        self.titleLabel?.font = UIFont(name: "RoadNumbersCyr-Regular", size: 30)
        let character = Character(String(digit))
        let title = String(Constants.pnLettersMap[character] ?? character)
        self.setTitle(title, for: .normal)
        self.setTitleColor(.label, for: .normal)
    }
    
    init(imageName: String, type: PNButtonType) {
        self.type = type
        self.bgColor = UIColor(named: "DarkKeyBackground")
        super.init(frame: .zero)
        self.setup()
        self.setImage(UIImage(systemName: imageName), for: .normal)
        self.tintColor = .label
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func setup(_ radius: CGFloat = 0.5) {
        self.rectLayer.cornerRadius = 6
        self.layer.addSublayer(self.rectLayer)
        self.imageView?.layer.zPosition = 2
        
        self.rectLayer.shadowColor   = UIColor.black.cgColor
        self.rectLayer.shadowOpacity = 0.4
        self.rectLayer.shadowOffset  = CGSize(width: 0.0, height : 1.0)
        self.rectLayer.shadowRadius  = radius
        
        self.addTarget(self, action: #selector(buttonDown), for: .touchDown)
        self.addTarget(self, action: #selector(buttonUp), for: [.touchUpInside, .touchUpOutside])
        self.addTarget(self, action: #selector(touchUpInside), for: .touchUpInside)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        self.rectLayer.backgroundColor = self.bgColor?.cgColor
        self.rectLayer.frame = self.layer.bounds.inset(by: UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4))
    }
    
    @objc func buttonDown(_ sender: PNButton) {
        sender.layer.opacity = 0.3
        self.timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { _ in
            self.waitCount += 1
            if self.waitCount > 5 {
                self.delegate?.buttonTapped(self)
            }
        })
    }
    
    @objc func buttonUp(_ sender: PNButton) {
        sender.layer.opacity = 1
        self.timer?.invalidate()
        self.timer = nil
        self.waitCount = 0
    }
    
    @objc func touchUpInside(_ sender: PNButton) {
        self.delegate?.buttonTapped(self)
    }
    
    func setBacgroundColor(color: UIColor) {
        self.bgColor = color
        self.setNeedsLayout()
    }
}

class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
    private weak var target: UIKeyInput?
    weak var delegate: PNKeyboardDelegate?
    
    init(target: UIKeyInput) {
        self.target = target
        super.init(frame: .zero)
        self.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        
        let blurEffectView = UIVisualEffectView(effect: UIBlurEffect())
        blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        self.addSubview(blurEffectView)
        
        self.setupButtons()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func setupButtons() {
        let letters: [PNButton] = Constants.pnLettersMap.keys.sorted().map { letter in
            let button = PNButton(letter: letter)
            button.delegate = self
            return button
        }
        let digits: [PNButton] = [1,2,3,4,5,6,7,8,9,0].map { digit in
            let button = PNButton(digit: digit)
            button.delegate = self
            return button
        }
        let backspace = PNButton(imageName: "delete.left", type: .backspace)
        backspace.delegate = self
        
        let done = PNButton(imageName: "arrow.turn.down.left", type: .done)
        done.delegate = self
        done.setBacgroundColor(color: .systemBlue)
        done.tintColor = .white
        
        let letterRows = [
            self.createLetterStack([letters[0], letters[1], letters[2]]),
            self.createLetterStack([letters[3], letters[4], letters[5]]),
            self.createLetterStack([letters[6], letters[7], letters[8]]),
            self.createLetterStack([letters[9], letters[10], letters[11]])
        ]
        
        let lettersStack = UIStackView(arrangedSubviews: letterRows)
        lettersStack.axis = .vertical
        lettersStack.distribution = .fillEqually
        //lettersStack.spacing = 8
        
        let digitRows = [
            self.createLetterStack([digits[0], digits[1], digits[2]]),
            self.createLetterStack([digits[3], digits[4], digits[5]]),
            self.createLetterStack([digits[6], digits[7], digits[8]]),
            self.createLetterStack([digits[9], backspace, done])
        ]
        
        let digitsStack = UIStackView(arrangedSubviews: digitRows)
        digitsStack.axis = .vertical
        digitsStack.distribution = .fillEqually
        //digitsStack.spacing = 8
        
        let mainStack = UIStackView(arrangedSubviews: [lettersStack, digitsStack])
        mainStack.spacing = 16
        mainStack.distribution = .fillEqually
        mainStack.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(mainStack)
        
        NSLayoutConstraint.activate([
            mainStack.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 16),
            mainStack.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -16),
            mainStack.topAnchor.constraint(equalTo: self.topAnchor, constant: 16),
            mainStack.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: -16)
        ])
    }
    
    func createLetterStack(_ views: [UIView]) -> UIStackView {
        let stack = UIStackView(arrangedSubviews: views)
        stack.distribution = .fillEqually
        //stack.spacing = 8
        return stack
    }
    
    // MARK: - PNButtonDelegate
    
    func buttonTapped(_ button: PNButton) {
        UIDevice.current.playInputClick()
        
        switch button.type {
        case .symbol(let s):
            self.target?.insertText(s)
        case .backspace:
            self.target?.deleteBackward()
        case .done:
            self.delegate?.returnClicked()
        }
    }
    
    // MARK: - UIInputViewAudioFeedback
    
    var enableInputClicksWhenVisible: Bool {
        return true
    }
}
