//
//  ScreenLockViewControllerSwift.swift
//  MCPlus
//
//  Created by seo ha on 14/02/2019.
//  Copyright © 2019 KangSH. All rights reserved.
//

import Foundation
import UIKit
import LocalAuthentication
import AudioToolbox

class ScreenLockViewController: UIViewController {
    @IBOutlet weak var topContainer:UIView!
    @IBOutlet weak var mainTitle:UILabel!
    @IBOutlet weak var subTitle:UILabel!
    @IBOutlet weak var password1:UIView!
    @IBOutlet weak var password2:UIView!
    @IBOutlet weak var password3:UIView!
    @IBOutlet weak var password4:UIView!
    @IBOutlet weak var password5:UIView!
    @IBOutlet weak var password6:UIView!
    @IBOutlet weak var warningText:UILabel!
    @IBOutlet weak var topMargin:NSLayoutConstraint!
    @IBOutlet weak var btnCancel:UIButton!
    
    let userDefaults = UserDefaults.standard
    var arrPreviousPassword = [Int]()
    var arrPassword = [Int]()
    
    deinit {
        Notification.removeNotification(observer: self)
    }
    
    func chargingPasswordViews(){
        print("chargingPasswordViews count: \(arrPassword.count)");
        
        switch arrPassword.count {
        case 0:
            self.password1.backgroundColor = UIColor.white
            self.password2.backgroundColor = UIColor.white
            self.password3.backgroundColor = UIColor.white
            self.password4.backgroundColor = UIColor.white
            self.password5.backgroundColor = UIColor.white
            self.password6.backgroundColor = UIColor.white
            break;
        case 1:
            self.password1.backgroundColor = UIColor.black
            self.password2.backgroundColor = UIColor.white
            self.password3.backgroundColor = UIColor.white
            self.password4.backgroundColor = UIColor.white
            self.password5.backgroundColor = UIColor.white
            self.password6.backgroundColor = UIColor.white
            break;
        case 2:
            self.password1.backgroundColor = UIColor.black
            self.password2.backgroundColor = UIColor.black
            self.password3.backgroundColor = UIColor.white
            self.password4.backgroundColor = UIColor.white
            self.password5.backgroundColor = UIColor.white
            self.password6.backgroundColor = UIColor.white
            break;
        case 3:
            self.password1.backgroundColor = UIColor.black
            self.password2.backgroundColor = UIColor.black
            self.password3.backgroundColor = UIColor.black
            self.password4.backgroundColor = UIColor.white
            self.password5.backgroundColor = UIColor.white
            self.password6.backgroundColor = UIColor.white
            break;
        case 4:
            self.password1.backgroundColor = UIColor.black
            self.password2.backgroundColor = UIColor.black
            self.password3.backgroundColor = UIColor.black
            self.password4.backgroundColor = UIColor.black
            self.password5.backgroundColor = UIColor.white
            self.password6.backgroundColor = UIColor.white
            break;
        case 5:
            self.password1.backgroundColor = UIColor.black
            self.password2.backgroundColor = UIColor.black
            self.password3.backgroundColor = UIColor.black
            self.password4.backgroundColor = UIColor.black
            self.password5.backgroundColor = UIColor.black
            self.password6.backgroundColor = UIColor.white
            break;
        case 6:
            self.password1.backgroundColor = UIColor.black
            self.password2.backgroundColor = UIColor.black
            self.password3.backgroundColor = UIColor.black
            self.password4.backgroundColor = UIColor.black
            self.password5.backgroundColor = UIColor.black
            self.password6.backgroundColor = UIColor.black
            break;
        default:
            break;
        }
    }
    
    func textRewrite(){
        let lockScreenDao = LockScreenDAO.sharedInstance
        
        if let pwInputType = lockScreenDao.pwInputType{
            switch pwInputType {
            case .FIRST_INPUT:
                self.mainTitle.text = "암호입력"
                self.subTitle.text = "암호를 입력해 주세요"
            case .CONFIRM_INPUT:
                self.mainTitle.text = "암호 재입력"
                self.subTitle.text = "확인을 위해 한 번 더 입력해 주세요"
            case .UNLOCK_INPUT:
                self.mainTitle.text = "암호입력"
                self.subTitle.text = "암호를 입력해 주세요"
            case .UNLOCK_FAIL_RE_INPUT:
                self.mainTitle.text = "암호입력"
                self.subTitle.text = "암호가 틀렸습니다. 다시 입력해 주세요"
            case .CHANGE_FIRST_INPUT:
                self.mainTitle.text = "새로운 암호입력"
                self.subTitle.text = "새로운 암호를 입력해 주세요"
            case .CHANGE_CONFIRM_INPUT:
                self.mainTitle.text = "새로운 암호 재입력"
                self.subTitle.text = "확인을 위해 한 번 더 입력해 주세요"
            }
        }
    }
}

extension ScreenLockViewController{
    func appWillEnterBackground(notification:Notification){
        print("will enter background notification")
        
        let lockScreenDao = LockScreenDAO.sharedInstance
        
        arrPreviousPassword = [Int]()
        arrPassword = [Int]()
        
        if let pwInputType = lockScreenDao.pwInputType{
            switch pwInputType {
            case .FIRST_INPUT:
                break
            case .CONFIRM_INPUT:
                lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.FIRST_INPUT
                lockScreenDao.saveOptionValuesWithoutPassword()
            case .UNLOCK_INPUT:
                break
            case .UNLOCK_FAIL_RE_INPUT:
                fallthrough
            case .CHANGE_FIRST_INPUT:
                fallthrough
            case .CHANGE_CONFIRM_INPUT:
                lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
                lockScreenDao.saveOptionValuesWithoutPassword()
                break
            }
        }
        
        self.textRewrite()
        self.chargingPasswordViews()
        
    }
    
    override func viewWillAppear(_ animated: Bool) {
        
        guard #available(iOS 11.0, *) else{ return }
        
        //지문인식
        let context = LAContext()
        var error2:NSError?
        guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error2) else {
            return
        }
        
        if context.biometryType == .faceID{
            return
        }
        
        let error:AutoreleasingUnsafeMutablePointer<NSError?>? = nil

        let temp = self.userDefaults.object(forKey: "fingerprint") as? String
        var isSwitchOn = true

        if let _temp = temp{
            isSwitchOn = temp != "OFF"
        }else{
            // 지문입력 받음
        }

        let lockScreenDao = LockScreenDAO.sharedInstance
        print("lockScreenDao.pwInputType >>>>>>>>>>>>> \(lockScreenDao.pwInputType)")

        // 지문입력은 락을 풀때만 사용해야 한다.
        var isUnlockStatus = false

        if lockScreenDao.pwInputType == LockScreenDAO.PASSWORD_INPUT_TYPE(rawValue: 2){
            isUnlockStatus = true
        }

        if isUnlockStatus, isSwitchOn, context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: error){
            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "지문을 입력해주세요") { (success, error) in
                if error != nil{
                    print("Touch 지원하지 않음")
                    return
                }

                guard success == true else{
                    print("@@@@실패")
                    return
                }

                print("@@@@성공") // 지문 인증 성공했을때
                let now = Date()
                let dateFormatString = "yyyy-MM-dd hh:mm:ss"
                let date = now.fromString(format: dateFormatString)
                print(date)

                // String으로 저장
                self.userDefaults.set(date, forKey: "fingerprintAuthTime")
                self.dismissSelf()

            }
        }
        
    }
    
    override func viewDidAppear(_ animated: Bool) {
        print("viewDidAppear")
    }
    
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        
        Notification.registerNotification(name: UIApplication.didEnterBackgroundNotification, queue: .main, block: appWillEnterBackground)
        
        let lockScreenDao = LockScreenDAO.sharedInstance
        
        //업데이트로 인한 초기화 (v4 비밀번호 4자리 -> 6자리 변경이슈)
        if isOlderVersionPassword(){
            lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.FIRST_INPUT
        }
        
        print("lockScreenDao.pwInputType >>>>>>>>>>>>> \(lockScreenDao.pwInputType)")
        
        self.btnCancel.isHidden = lockScreenDao.pwInputType != LockScreenDAO.PASSWORD_INPUT_TYPE.CHANGE_FIRST_INPUT &&
            lockScreenDao.pwInputType != LockScreenDAO.PASSWORD_INPUT_TYPE.CHANGE_CONFIRM_INPUT
        
        switch Constants.kScreenHeight {
        case ...568:
            self.topMargin.constant = 40
        case ...480:
            self.topMargin.constant = 30
        default:
            break
        }
        
        self.password1.layer.cornerRadius = 10.0
        self.password1.layer.masksToBounds = true
        
        self.password2.layer.cornerRadius = 10.0
        self.password2.layer.masksToBounds = true
        
        self.password3.layer.cornerRadius = 10.0
        self.password3.layer.masksToBounds = true
        
        self.password4.layer.cornerRadius = 10.0
        self.password4.layer.masksToBounds = true
        
        self.password5.layer.cornerRadius = 10.0
        self.password5.layer.masksToBounds = true
        
        self.password6.layer.cornerRadius = 10.0
        self.password6.layer.masksToBounds = true
        
        lockScreenDao.loadOptionValues()
        if let pwInputType = lockScreenDao.pwInputType{
            switch pwInputType {
            case .FIRST_INPUT:
                break
            case .CONFIRM_INPUT:
                lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.FIRST_INPUT
                lockScreenDao.saveOptionValuesWithoutPassword()
            case .UNLOCK_INPUT:
                break
            case .UNLOCK_FAIL_RE_INPUT:
                lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
                lockScreenDao.saveOptionValuesWithoutPassword()
            case .CHANGE_FIRST_INPUT:
                break
            case .CHANGE_CONFIRM_INPUT:
                break
            }
        }
        
        self.textRewrite()
        self.chargingPasswordViews()
        
    }
    
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func savePasswordOnArray(number:Int){
        let lockScreenDao = LockScreenDAO.sharedInstance
        
        print("arrPassword count: \(arrPassword.count)")
        print("lockScreenDao.pwInputType : \(lockScreenDao.pwInputType)")
        
        switch arrPassword.count {
        case ..<6:
            arrPassword.append(number)
            
            //뷰 초기화
            self.chargingPasswordViews()
            self.printPassword()
            self.printPreviousPassword()
            
            Thread.sleep(forTimeInterval: 0.1)
            if arrPassword.count == 6{
                fallthrough
            }
        case 6:
            if let pwInputType = lockScreenDao.pwInputType{
                switch pwInputType {
                case .FIRST_INPUT:
                    let pw = self.arrPassword.reduce("", {"\($0)\($1)"})
                    guard self.isValidNumber(pw: pw) else{
                        arrPassword = [Int]()
                        self.textRewrite()
                        self.mainTitle.text = "암호입력"
                        self.subTitle.text = "연속된 암호를 사용할 수 없습니다. 다시 입력해 주세요"
                        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
                        //뷰 초기화
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
                            self?.chargingPasswordViews()
                        }
                        return
                    }
                    
                    //처음 암호를 입력했을 때, 확인모드로 변경.
                    lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.CONFIRM_INPUT
                    self.textRewrite()
                    
                    //암호 입력 새로 받음
                    arrPreviousPassword = arrPassword.map({$0})
                    arrPassword = [Int]()
                    
                    //뷰 초기화
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
                        self?.chargingPasswordViews()
                    }
                    
                case .CONFIRM_INPUT:
                    // 암호가 일치하는지 판단
                    if self.comparePasswords(){
                        // 패스워드 저장 후 모달창 닫음.
                        lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
                        lockScreenDao.saveOptionValues(arrPassword: arrPassword)
                        
                        //뷰 초기화
                        self.chargingPasswordViews()
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
                            self?.dismissSelf()
                        }
                    
                    }else{
                        // 처음부터 다시 입력 받음
                        lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.FIRST_INPUT
                        
                        self.mainTitle.text = "암호입력"
                        self.subTitle.text = "암호가 틀렸습니다. 다시 입력해 주세요"
                        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
                        
                        self.printPassword()
                        self.printPreviousPassword()
                        
                        arrPreviousPassword = [Int]()
                        arrPassword = [Int]()
                        
                        //뷰 초기화
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
                            self?.chargingPasswordViews()
                        }
                        
                    }
                case .UNLOCK_INPUT:
                    print("UNLOCK_INPUT 1")
                    
                    // 암호가 일치하는지 판단
                    if self.comparePasswordWithStorage(){
                        //모달창 닫음.
                        print("UNLOCK_INPUT 2")
                        // 패스워드 저장 후 모달창 닫음.
                        lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
                        lockScreenDao.saveOptionValuesWithoutPassword()
                        
                        print("UNLOCK_INPUT 3")
                        //뷰 초기화
                        self.chargingPasswordViews()
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
                            self?.dismissSelf()
                        }
                    }else{
                        //초기화 하고 다시 입력 받음
                        lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_FAIL_RE_INPUT
                        arrPassword = [Int]()
                        
                        self.mainTitle.text = "암호입력"
                        self.subTitle.text = "암호가 틀렸습니다. 다시 입력해 주세요"
                        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
                        
                        self.printPassword()
                        self.printPreviousPassword()
                        
                        //뷰 초기화
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
                            self?.chargingPasswordViews()
                        }
                    }
                    
                case .UNLOCK_FAIL_RE_INPUT:
                    if self.comparePasswordWithStorage(){
                        lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
                        lockScreenDao.saveOptionValuesWithoutPassword()
                        
                        //모달창 닫음.
                        //뷰 초기화
                        self.chargingPasswordViews()
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
                            self?.dismissSelf()
                        }
                    }else{
                        //초기화 하고 다시 입력 받음
                        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
                        lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_FAIL_RE_INPUT
                        arrPassword = [Int]()
                        
                        //뷰 초기화
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
                            self?.chargingPasswordViews()
                        }
                    }
                   
                case .CHANGE_FIRST_INPUT:
                    //처음 암호를 입력했을 때, 변경확인모드로 변경.
                    lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.CHANGE_CONFIRM_INPUT
                    self.textRewrite()
                    
                    //암호 입력 새로 받음
                    arrPreviousPassword = [Int]()
                    arrPassword = [Int]()
                    
                    //뷰 초기화
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
                        self?.chargingPasswordViews()
                    }
                    
                case .CHANGE_CONFIRM_INPUT:
                    // 암호가 일치하는지 판단
                    if self.comparePasswords(){
                        // 패스워드 저장 후 모달창 닫음.
                        lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
                        lockScreenDao.saveOptionValues(arrPassword: arrPassword)
                        
                        //뷰 초기화
                        self.chargingPasswordViews()
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
                            self?.dismissSelf()
                        }
                    }else{
                        // 처음부터 다시 입력 받음
                        lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.CHANGE_FIRST_INPUT
                        self.mainTitle.text = "새로운 암호입력"
                        self.subTitle.text = "암호가 틀렸습니다. 새로운 암호를 입력해 주세요"
                        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
                        
                        self.printPassword()
                        self.printPreviousPassword()
                        
                        arrPreviousPassword = [Int]()
                        arrPassword = [Int]()
                        
                        //뷰 초기화
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
                            self?.chargingPasswordViews()
                        }
                    }
                    
                }
            }
        default:
            break
        }
        
        
    }
    
    func comparePasswords() -> Bool {
        print("comparePasswords start")
        
        let pw1 = arrPreviousPassword.reduce("", {"\($0)\($1)"})
        let pw2 = arrPassword.reduce("", {"\($0)\($1)"})
        
        print("comparePasswords end")
        return pw1 == pw2
        
    }
    
    func comparePasswordWithStorage() -> Bool{
        
        var isEncEqual = false
        
        let lockScreenDao = LockScreenDAO.sharedInstance
        
        //암호화 라이브러리 RNCrypter는 랜덤 salt를 쓰므로 복호화를 통하여 암호 비교
        let pw1 = arrPassword.reduce("", {"\($0)\($1)"})
        let pw2 = [0, 1, 2, 3, 4, 5].map({lockScreenDao.encryptedPasswordWithKey(key: "\($0)")})
            .compactMap({$0})
            .map({$0.decryptWithKey(key: Constants.PACS_APP_ENC_KEY)})
            .compactMap({$0})
            .reduce("", {"\($0)\($1)"})
        print("\(pw1),\(pw2)")
        isEncEqual = pw1 == pw2
        print("암호화된 키가 일치하는가?> \(isEncEqual ? "참" : "거짓")")
        return isEncEqual
        
    }
    
    func isValidNumber(pw:String) -> Bool {
        print(pw)
        let pwRegEx = "^(?!.*?(?:0(?:12|98)|123|234|3(?:45|21)|4(?:56|32)|5(?:67|43)|6(?:78|54)|7(?:89|65)|876|987))(?!.*?(.)\\1{2})[0-9]{6}"
        let pwTest  = NSPredicate(format:"SELF MATCHES %@", pwRegEx)
        return pwTest.evaluate(with: pw)
    }
    
    
    func dismissSelf(){
        Notification.removeNotification(observer: self)
        self.dismiss(animated: false, completion: nil)
    }
    
    
    
    func printPassword(){
        for i in 0..<arrPassword.count{
            print("[arrPassword \(i)] = \(arrPassword[i])")
        }
        print("===========================\n")
    }
    
    func printPreviousPassword(){
        for i in 0..<arrPreviousPassword.count{
            print("[arrPreviousPassword \(i)] = \(arrPreviousPassword[i])")
        }
        print("===========================\n")
    }
    
    // MARK: - <Numberpad Functions>
    
    @IBAction func clickNum1(sender:Any?){
        self.savePasswordOnArray(number: 1)
    }
    
    @IBAction func clickNum2(sender:Any?){
        self.savePasswordOnArray(number: 2)
    }
    
    @IBAction func clickNum3(sender:Any?){
        self.savePasswordOnArray(number: 3)
    }
    
    @IBAction func clickNum4(sender:Any?){
        self.savePasswordOnArray(number: 4)
    }
    
    @IBAction func clickNum5(sender:Any?){
        self.savePasswordOnArray(number: 5)
    }
    
    @IBAction func clickNum6(sender:Any?){
        self.savePasswordOnArray(number: 6)
    }
    
    @IBAction func clickNum7(sender:Any?){
        self.savePasswordOnArray(number: 7)
    }
    
    @IBAction func clickNum8(sender:Any?){
        self.savePasswordOnArray(number: 8)
    }
    
    @IBAction func clickNum9(sender:Any?){
        self.savePasswordOnArray(number: 9)
    }
    
    @IBAction func clickNum0(sender:Any?){
        self.savePasswordOnArray(number: 0)
    }
    
    @IBAction func clickNumBackspace(sender:Any?){
        let count = arrPassword.count
        
        if count > 0{
            arrPassword.removeLast()
        }
        
        self.chargingPasswordViews()
        self.printPassword()
    }
    
    @IBAction func clickNumCancel(sender:Any?){
        print("취소")
        let lockScreenDao = LockScreenDAO.sharedInstance
        lockScreenDao.pwInputType = LockScreenDAO.PASSWORD_INPUT_TYPE.UNLOCK_INPUT
        
        //뷰 초기화
        self.chargingPasswordViews()
        self.dismissSelf()
    }
    
    func isOlderVersionPassword() -> Bool{
        let lockScreenDao = LockScreenDAO.sharedInstance
        
        let pw = [0, 1, 2, 3, 4, 5].map({lockScreenDao.encryptedPasswordWithKey(key: "\($0)")})
            .compactMap({$0})
            .map({$0.decryptWithKey(key: Constants.PACS_APP_ENC_KEY)})
            .compactMap({$0})
            .reduce("", {"\($0)\($1)"})
        
        return pw.count == 4
    }
    
    



}
