//
//  PGPKeyArmorSettingTableViewController.swift
//  pass
//
//  Created by Mingshen Sun on 17/2/2017.
//  Copyright © 2017 Bob Sun. All rights reserved.
//

import UIKit
import passKit

class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
    @IBOutlet weak var armorPublicKeyTextView: UITextView!
    @IBOutlet weak var armorPrivateKeyTextView: UITextView!
    @IBOutlet weak var scanPublicKeyCell: UITableViewCell!
    @IBOutlet weak var scanPrivateKeyCell: UITableViewCell!
    
    var pgpPassphrase: String?
    let passwordStore = PasswordStore.shared
    
    class ScannedPGPKey {
        static let maxNumberOfGif = 100
        enum KeyType {
            case publicKey, privateKey
        }
        var keyType = KeyType.publicKey
        var numberOfSegments = 0
        var previousSegment = ""
        var key = ""
        var message = ""
        var hasStarted = false
        var isDone = false
        
        func reset(keytype: KeyType) {
            self.keyType = keytype
            numberOfSegments = 0
            previousSegment = ""
            key = ""
            message = "Looking for the starting frame."
            hasStarted = false
            isDone = false
        }
        
        func addSegment(segment: String) {
            // skip duplicated segments
            guard segment != previousSegment else {
                return
            }
            previousSegment = segment
            
            // check whether we have found the first block
            if hasStarted == false {
                let findPublic = segment.contains("-----BEGIN PGP PUBLIC KEY BLOCK-----")
                let findPrivate = segment.contains("-----BEGIN PGP PRIVATE KEY BLOCK-----")
                switch keyType {
                case .publicKey:
                    if findPrivate {
                        message = "Please scan public key."
                    }
                    hasStarted = findPublic
                case .privateKey:
                    if findPublic {
                        message = "Please scan private key."
                    }
                    hasStarted = findPrivate
                }
            }
            guard hasStarted == true else {
                return
            }
            
            // check the number of segments
            numberOfSegments = numberOfSegments + 1
            guard numberOfSegments <= ScannedPGPKey.maxNumberOfGif else {
                key = "Too many QR codes"
                return
            }
            
            // update full text and check whether we are done
            key.append(segment)
            if key.contains("-----END PGP PUBLIC KEY BLOCK-----") || key.contains("-----END PGP PRIVATE KEY BLOCK-----") {
                isDone = true
            }
            
            // update message
            message = "\(numberOfSegments) scanned QR codes."
        }
    }
    var scanned = ScannedPGPKey()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        armorPublicKeyTextView.text = SharedDefaults[.pgpPublicKeyArmor]
        armorPrivateKeyTextView.text = SharedDefaults[.pgpPrivateKeyArmor]
        pgpPassphrase = passwordStore.pgpKeyPassphrase
        
        scanPublicKeyCell?.textLabel?.text = "Scan Public Key QR Codes"
        scanPublicKeyCell?.textLabel?.textColor = Globals.blue
        scanPublicKeyCell?.selectionStyle = .default
        scanPublicKeyCell?.accessoryType = .disclosureIndicator

        scanPrivateKeyCell?.textLabel?.text = "Scan Private Key QR Codes"
        scanPrivateKeyCell?.textLabel?.textColor = Globals.blue
        scanPrivateKeyCell?.selectionStyle = .default
        scanPrivateKeyCell?.accessoryType = .disclosureIndicator
    }
    
    @IBAction func save(_ sender: Any) {
        guard armorPublicKeyTextView.text.isEmpty == false else {
            Utils.alert(title: "Cannot Save", message: "Please set public key first.", controller: self, completion: nil)
            return
        }
        guard armorPrivateKeyTextView.text.isEmpty == false else {
            Utils.alert(title: "Cannot Save", message: "Please set private key first.", controller: self, completion: nil)
            return
        }
        let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert)
        // no
        savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
            self.pgpPassphrase = nil
            SharedDefaults[.isRememberPGPPassphraseOn] = false
            self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
        })
        // yes
        savePassphraseAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive) {_ in
            // ask for the passphrase
            let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
                self.pgpPassphrase = alert.textFields?.first?.text
                SharedDefaults[.isRememberPGPPassphraseOn] = true
                self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
            }))
            alert.addTextField(configurationHandler: {(textField: UITextField!) in
                textField.text = self.pgpPassphrase
                textField.isSecureTextEntry = true
            })
            self.present(alert, animated: true, completion: nil)
        })
        self.present(savePassphraseAlert, animated: true, completion: nil)
    }
    
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if text == UIPasteboard.general.string {
            // user pastes something, do the copy here again and clear the pasteboard in 45s
            SecurePasteboard.shared.copy(textToCopy: text)
        }
        return true
    }
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let selectedCell = tableView.cellForRow(at: indexPath)
        if selectedCell == scanPublicKeyCell {
            scanned.reset(keytype: ScannedPGPKey.KeyType.publicKey)
            self.performSegue(withIdentifier: "showPGPScannerSegue", sender: self)
        } else if selectedCell == scanPrivateKeyCell {
            scanned.reset(keytype: ScannedPGPKey.KeyType.privateKey)
            self.performSegue(withIdentifier: "showPGPScannerSegue", sender: self)
        }
        tableView.deselectRow(at: indexPath, animated: true)
    }
    
    // MARK: - QRScannerControllerDelegate Methods
    func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
        scanned.addSegment(segment: line)
        if scanned.isDone {
            return (accept: true, message: "Done")
        } else {
            return (accept: false, message: scanned.message)
        }
    }
    
    // MARK: - QRScannerControllerDelegate Methods
    func handleScannedOutput(line: String) {
        switch scanned.keyType {
        case .publicKey:
            armorPublicKeyTextView.text = scanned.key
        case .privateKey:
            armorPrivateKeyTextView.text = scanned.key
        }
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showPGPScannerSegue" {
            if let navController = segue.destination as? UINavigationController {
                if let viewController = navController.topViewController as? QRScannerController {
                    viewController.delegate = self
                }
            } else if let viewController = segue.destination as? QRScannerController {
                viewController.delegate = self
            }
        }
    }
}
