//
//  ContactListViewModel.swift


import Foundation
import ContactsUI
import SSSpinnerButton
import PhoneNumberKit
import MessageUI

class ContactListViewModel : NSObject{
    
    static let shared = ContactListViewModel()
    var contactData : BoxBind<[CNContact]> = BoxBind([CNContact]())
    var arrSearchContactData : BoxBind<[CNContact]> = BoxBind([CNContact]())
    var userInfoData : BoxBind<[User]> = BoxBind([User]())
    
    let userDefaultManager = UserDefaultManager.shared
    let phoneNumberKit = PhoneNumberKit()
    
    override init() {
        super.init()
        self.getUserInfoData()
//        self.checkAuthorizationStatus()
    }
    
    func checkAuthorizationStatus(){
        let authorizationStatus = CNContactStore.authorizationStatus(for: CNEntityType.contacts)

        switch authorizationStatus {
        case .authorized:
            debugPrint("Contact Data")
//            self.getContactList()
            self.getContactList { success in
            }
        case .notDetermined:
            debugPrint("Contact permission is not granted")
        default:
            break
        }
    }
    
    func getUserInfoData(){
        let decoder = JSONDecoder()
        do{
            let jsonData = try decoder.decode(UserInfoAPIModel.self, from: self.userDefaultManager.loginUserData)
            if let userData = jsonData.user{
                self.userInfoData.value.append(userData)
            }
        }
        catch{
            debugPrint("Error in parse user model")
        }
    }
    
    func getContactList(){
        let fetchRequest = CNContactFetchRequest(keysToFetch:[CNContactVCardSerialization.descriptorForRequiredKeys()])
        
        let contactStore = CNContactStore()
        do {
            try contactStore.enumerateContacts(with: fetchRequest, usingBlock: { (contact, pointer) -> Void in
                debugPrint("contact = ","\(contact)")
                
                self.contactData.value.append(contact)
                self.arrSearchContactData.value.append(contact)
            })
        }
        catch {
            debugPrint("Unable to fetch contacts")
        }
    }
    
    func getContactList(isSearchActive : Bool = false,arrFriendList : [FriendListModel]? = nil, arrPendingList : [PendingFriendReqListModel]? = nil, arrFriendReqList : [ReceivedReqListModel]? = nil, success :@escaping(Bool)->()){
//        self.arrContactList.value = []
            self.contactData.value = []
          //  self.arrSearchContactData.value = []
        let fetchRequest = CNContactFetchRequest(keysToFetch:[CNContactVCardSerialization.descriptorForRequiredKeys()])
            let contactStore = CNContactStore()
        DispatchQueue.global(qos: .userInitiated).async {
            do {
                try contactStore.enumerateContacts(with: fetchRequest, usingBlock: { (contact, pointer) -> Void in
                    
                    DispatchQueue.main.async {
                        if contact.phoneNumbers != []{
                           // if !isSearchActive{
                                if !self.contactData.value.contains(where: { $0.givenName == contact.givenName }){
                                    if !self.contactData.value.contains(where: { $0.phoneNumbers == contact.phoneNumbers }){
                                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                                            debugPrint("arrContactList ====","\(contact)")
                                            let isNotAvailable = self.getFillterDataFromContactList(arrFriendList: arrFriendList, arrPendingList: arrPendingList, arrFriendReqList: arrFriendReqList, dataContact: contact)
                                            if isNotAvailable{
                                                self.contactData.value.append(contact)
                                                self.contactData.value = self.contactData.value.sorted{ $0.givenName.lowercased() < $1.givenName.lowercased() }
                                            }
                                        }
                                    }
                                }
                           // }
                            DispatchQueue.main.async{
                                if isSearchActive{
                                    for (index,arr) in self.arrSearchContactData.value.enumerated(){
                                        if contact.identifier == arr.identifier{
                                            if contact.phoneNumbers != arr.phoneNumbers{
                                                self.arrSearchContactData.value[index] = contact
                                            }else if contact.givenName != arr.givenName{
                                                self.arrSearchContactData.value[index] = contact
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
//                    DispatchQueue.main.async {
//
//                    }
                })
                
            }
            catch {
                debugPrint("Unable to fetch contacts")
            }
           /* self.isShowContactView = true*/
//            self.removeSelfContactData()
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.02) {
                success(true)
            }
        }
    }
    
    func getFillterDataFromContactList(arrFriendList : [FriendListModel]?, arrPendingList : [PendingFriendReqListModel]?, arrFriendReqList : [ReceivedReqListModel]?, dataContact : CNContact) -> Bool{
        
//        let filterData = self.contactData.value.filter { dataContact in
            
            if !dataContact.phoneNumbers.isEmpty{
             
                var isContainsFriend = true
                var isContainsPending = true
                var isContainsReqList = true
                
                //Remove friend list data from contact list
                if let friendList = arrFriendList{
                    isContainsFriend = !friendList.contains { friendData in
                        
                        let concatenatedStr = (friendData.country_code ?? "") + (friendData.phone ?? "")
                        let contactNo = (dataContact.phoneNumbers[0].value).value(forKey: "digits") as? String ?? ""
                        
                        if contactNo.hasPrefix("+"){
                            let contactNumber = self.parsePhoneNumber(phoneNo: (dataContact.phoneNumbers[0].value).value(forKey: "digits") as? String ?? "", country: (dataContact.phoneNumbers[0].value).value(forKey: "countryCode") as? String ?? "")
                            return concatenatedStr == contactNumber?.numberString
                        }
                        else{
                            return friendData.phone == contactNo
                        }
                    }
                }
                
                //Remove pending req data from contact list
                if let pendingList = arrPendingList{
                    isContainsPending = !pendingList.contains(where: { pendingData in
                        
                        let concatenatedStr = (pendingData.country_code ?? "") + (pendingData.phone ?? "")
                        let contactNo = (dataContact.phoneNumbers[0].value).value(forKey: "digits") as? String ?? ""
                        
                        if contactNo.hasPrefix("+"){
                            let contactNumber = self.parsePhoneNumber(phoneNo: (dataContact.phoneNumbers[0].value).value(forKey: "digits") as? String ?? "", country: (dataContact.phoneNumbers[0].value).value(forKey: "countryCode") as? String ?? "")
                            return concatenatedStr == contactNumber?.numberString
                        }
                        else{
                            return pendingData.phone == contactNo
                        }
                    })
                }
                
                //Remove pending req data from contact list
                if let friendReqList = arrFriendReqList{
                    isContainsReqList = !friendReqList.contains(where: { requestData in
                        
                        let concatenatedStr = (requestData.country_code ?? "") + (requestData.phone ?? "")
                        let contactNo = (dataContact.phoneNumbers[0].value).value(forKey: "digits") as? String ?? ""
                        
                        if contactNo.hasPrefix("+"){
                            let contactNumber = self.parsePhoneNumber(phoneNo: (dataContact.phoneNumbers[0].value).value(forKey: "digits") as? String ?? "", country: (dataContact.phoneNumbers[0].value).value(forKey: "countryCode") as? String ?? "")
                            return concatenatedStr == contactNumber?.numberString
                        }
                        else{
                            return requestData.phone == contactNo
                        }
                    })
                }
                
                //Remove Logged in User from contact list
                let isUserContains = !self.userInfoData.value.contains { user in
                    
                    let concatenatedStr = (user.country_code ?? "") + (user.phone ?? "")
                    let contactNo = (dataContact.phoneNumbers[0].value).value(forKey: "digits") as? String ?? ""
                    
                    if contactNo.hasPrefix("+"){
                        let contactNumber = self.parsePhoneNumber(phoneNo: (dataContact.phoneNumbers[0].value).value(forKey: "digits") as? String ?? "", country: (dataContact.phoneNumbers[0].value).value(forKey: "countryCode") as? String ?? "")
                        return concatenatedStr == contactNumber?.numberString
                    }
                    else{
                        return user.phone == contactNo
                    }
                }
                return isContainsFriend && isContainsPending && isUserContains && isContainsReqList
            }
            else{
                return false
            }
//        }
        
//        return
//        self.callToViewModelForUIUpdate()
    }
    
    func showActionSheet(index : Int){
        var arrFilterData = [CNContact]()
//              if arrSearchContactData.value.count != 0{
//                  arrFilterData = arrSearchContactData.value
//              }else{
//                  arrFilterData = contactData.value
//              }
        arrFilterData =  arrSearchContactData.value.count != 0 ? arrSearchContactData.value : contactData.value
        
        let actionSheet = UIAlertController(title: Alert_Message.addFriendAlertTitle, message: "Make sure \(arrFilterData[index].givenName )'s number is entered correctly in your Contact. Sometimes you just have to add a '+' at the start of the number. Then, restart the app and try again.", preferredStyle: .alert)

        let cancelAction = UIAlertAction(title: Alert_Message.Ok, style: .cancel) { (action) in
            debugPrint("didPress cancel")
        }
        
        actionSheet.addAction(cancelAction)

        if let currentVC = UIApplication.shared.topViewController() as? ContactListViewController {
            currentVC.present(actionSheet, animated: true, completion: nil)
        }
    }
    
    func presentiMessageController(contactNo : String){
        
        if (MFMessageComposeViewController.canSendText()) {
            let controller = MFMessageComposeViewController()
            controller.body = "I added you to my \(APP_NAME_WITH_WIDGET).\nDownload the app to accept\n\(APP_STORE_LINK)"
            controller.recipients = [contactNo]
            
            if let currentVC = UIApplication.shared.topViewController() as? ContactListViewController {
                controller.messageComposeDelegate = currentVC
                controller.modalPresentationStyle = .pageSheet
                currentVC.present(controller, animated: true, completion: nil)
            }
        }
    }
    
    func parsePhoneNumber(phoneNo: String, country: String) -> PhoneNumber?{
        do{
            let phoneNumber = try phoneNumberKit.parse(phoneNo)
            return phoneNumber
        }
        catch {
            debugPrint("Generic parser error")
        }
        return nil
    }
    
    @objc func callAddFriendAPI(_ sender: UITapGestureRecognizer) {
        var isSearchActive = false
        if let sender = sender as? CustomTapGesture {
            if !sender.contactData[sender.index].phoneNumbers.isEmpty{
                if let contactData = UIApplication.getTopViewController() as? ContactListViewController{
                  isSearchActive = !(contactData.searchbar.text?.isEmpty ?? false)
                }
                var phoneNumber = isSearchActive ? (arrSearchContactData.value[sender.index].phoneNumbers[0].value).value(forKey: "digits") as? String ?? "" : (sender.contactData[sender.index].phoneNumbers[0].value).value(forKey: "digits") as? String ?? ""
                var countryCode  = isSearchActive ? (arrSearchContactData.value[sender.index].phoneNumbers[0].value).value(forKey: "countryCode") as? String ?? "" : (sender.contactData[sender.index].phoneNumbers[0].value).value(forKey: "countryCode") as? String ?? ""
                
                let userCountryCode = self.phoneNumberKit.countryCode(for: countryCode)
                let contactNumber = parsePhoneNumber(phoneNo: phoneNumber , country: countryCode)
                
                if contactNumber != nil{
                    phoneNumber = contactNumber?.numberString ?? ""
                    countryCode = "+\(contactNumber?.countryCode ?? 1)"//"+\(userCountryCode ?? 1)"
                }else{
                    countryCode = "+\(userCountryCode ?? 1)"//"+\(contactNumber?.countryCode ?? 1)"
                }
                                
//                if let contactNumber = parsePhoneNumber(phoneNo: isSearchActive ? (arrSearchContactData.value[sender.index].phoneNumbers[0].value).value(forKey: "digits") as? String ?? "" : (sender.contactData[sender.index].phoneNumbers[0].value).value(forKey: "digits") as? String ?? ""  , country: isSearchActive ? (arrSearchContactData.value[sender.index].phoneNumbers[0].value).value(forKey: "countryCode") as? String ?? "" : (sender.contactData[sender.index].phoneNumbers[0].value).value(forKey: "countryCode") as? String ?? "" ){

                    sender.addBtn.startAnimate(spinnerType: .ballRotateChase, spinnercolor: .gray, spinnerSize: 10, complete: nil)
                    
                    if Reachability.isInternetAvailable {
                        
                        APIDataManager.shared.callSendFriendRequestAPI(phonoNo: phoneNumber, countryCode: countryCode) { (success) in
                            
                            sender.addBtn.stopAnimate {
                                
                                if success == true{
                                    if self.arrSearchContactData.value.count != 0{
                                     let removeContact = self.contactData.value.filter({$0.identifier == self.arrSearchContactData.value[sender.index].identifier })
                                        for arrSearch in removeContact{
                                            self.contactData.value.removeObject(object: arrSearch)
                                        }
                                        self.arrSearchContactData.value.remove(at: sender.index)
                                        
                                    }else{
                                        self.contactData.value.remove(at: sender.index)
                                    }
                      
                                    if UserDefaultManager.shared.isHideCustomReview == false && FIRRemoteManagement.shared.isShow_CustomReviewPopup{
                                       // ScreenManager.shared.moveToCustomRating()
                                        debugPrint("Open Custom Review by adding new friend")
                                    }
                                    if FIRRemoteManagement.shared.isShow_NativeReviewPopup{
                                        ScreenManager.shared.showNativeReviewPopup()
                                    }
                                }
                                else{
                                    self.presentiMessageController(contactNo: contactNumber?.numberString ?? "")
                                }
                            }
                        }
                    }
                    else{
                        Utilities.showAlertView(nil, Alert_Message.networkAlertMsg) { value in
                            sender.addBtn.stopAnimate(complete: nil)
                        }
                    }
//                }
//                else{
//                    self.showActionSheet(index: sender.index)
//                }
            }
            else{
                self.showActionSheet(index: sender.index)
            }
        }
    }
}

extension ContactListViewModel{
    
    //MARK: - Datasource & Delegate -
    
    func getCellCountForDisplay(isFromSearch : Bool) -> Int{
        if isFromSearch{
            return self.arrSearchContactData.value.count
        }
        else{
            return self.contactData.value.count
        }
    }
    
    func perpareCellForDisplay(tableView: UITableView, indexPath: IndexPath, contactData: [CNContact]) -> UITableViewCell{
        
        let cell = tableView.dequeueReusableCell(withIdentifier: AddFriendTVCell.identifier, for: indexPath) as! AddFriendTVCell
        if contactData[indexPath.row].givenName == ""{
            cell.contactName.text = contactData[indexPath.row].phoneNumbers[0].value.stringValue
        }else{
            cell.contactName.text = "\(contactData[indexPath.row].givenName) \(contactData[indexPath.row].familyName)"
        }
      
        cell.btnAdd.tag = indexPath.row
        cell.selectionStyle = .none
        let tapGesture = CustomTapGesture(target: self, action: #selector(callAddFriendAPI(_:)))
        tapGesture.contactData = contactData
        tapGesture.index = indexPath.row
        tapGesture.addBtn = cell.btnAdd
        cell.btnAdd.addGestureRecognizer(tapGesture)
       
        if contactData[indexPath.row].givenName != "" {
            if contactData[indexPath.row].givenName[0].fisrtCharacterIsAlphabet{
        //    if contactData[indexPath.row].givenName != "" {
                cell.imgAvtar.image = UIImage(named: "add_friend_icon")
                cell.contactPrefix.text = contactData[indexPath.row].givenName[0]
            }else{
                cell.imgAvtar.image = UIImage(named: "avtar")
                cell.contactPrefix.text = ""
            }
        }else{
            cell.imgAvtar.image = UIImage(named: "avtar")
            cell.contactPrefix.text = ""
        }
       
        return cell
    }
}

fileprivate class CustomTapGesture: UITapGestureRecognizer {
    var contactData = [CNContact]()
    var index = 0
    var addBtn : SSSpinnerButton!
}
