//
//  ContactManager.swift
//  PhoneManager
//
//  Created by edy on 2025/5/8.
//

import Foundation
import Contacts
import ContactsUI

enum ContactError: Error {
    case unauthorized
    case contactNotFound(ContactModel)
    case executionFailed(Error)
}

enum MergePolicy {
    case union // 合并所有非空字段
    case priority(ContactModel) // 指定优先级联系人
}

enum ContactMergeError: Error {
    case unauthorized
    case emptyGroup
    case contactNotFound(identifier: String)
    case mergeConflict(field: String)
    case systemError(Error)
}


class ContactManager {
    
    
    // MARK: 删除联系人
    static func batchDeleteContacts( _ contacts: [ContactModel],completion: @escaping (Result<[ContactModel], ContactError>) -> Void) {
        let store = CNContactStore()
        let queue = DispatchQueue(label: "com.contacts.deleteQueue", qos: .userInitiated)
        
        queue.async {
            // 前置权限检查
            guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
                DispatchQueue.main.async {
                    completion(.failure(.unauthorized))
                }
                return
            }
            
            do {
                let result = try performAtomicDeletion(store: store, contacts: contacts)
                DispatchQueue.main.async {
                    completion(.success(result))
                }
            } catch let error as ContactError {
                DispatchQueue.main.async {
                    completion(.failure(error))
                }
            } catch {
                DispatchQueue.main.async {
                    completion(.failure(.executionFailed(error)))
                }
            }
        }
    }
    private static func performAtomicDeletion(store: CNContactStore, contacts: [ContactModel]) throws -> [ContactModel] {
        let batchSize = 200
        var deletedContacts = [ContactModel]()
        
        for batch in contacts.chunked(into: batchSize) {
            let identifiers = batch.map { $0.identifier }
            
            // 批量获取联系人
            let predicate = CNContact.predicateForContacts(withIdentifiers: identifiers)
            let matchedContacts = try store.unifiedContacts(
                matching: predicate,
                keysToFetch: [CNContactIdentifierKey as CNKeyDescriptor]
            )
            
            // 验证完整性
            let matchedIDs = Set(matchedContacts.map { $0.identifier })
            if let missing = batch.first(where: { !matchedIDs.contains($0.identifier) }) {
                throw ContactError.contactNotFound(missing)
            }
            
            // 执行删除
            let saveRequest = CNSaveRequest()
            matchedContacts.forEach {
                saveRequest.delete($0.mutableCopy() as! CNMutableContact)
            }
            
            try store.execute(saveRequest)
            deletedContacts.append(contentsOf: batch)
        }
        
        return deletedContacts
    }
    
    
    // MARK: 合并联系人
    static func mergeContacts(groups: [[ContactModel]],mergePolicy: MergePolicy = .union,completion: @escaping (Result<[String],ContactMergeError>) -> Void) {
        let store = CNContactStore()
        let queue = DispatchQueue(label: "com.contacts.mergeQueue", qos: .userInitiated)
        
        queue.async {
            // 权限检查
            guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
                DispatchQueue.main.async { completion(.failure(.unauthorized)) }
                return
            }
            
            do {
                var mergedIDs = [String]()
                let saveRequest = CNSaveRequest()
                
                try groups.forEach { group in
                    guard !group.isEmpty else { throw ContactMergeError.emptyGroup }
                    
                    // 获取原始联系人
                    let contacts = try fetchContacts(for: group, store: store)
                    
                    // 创建合并后的联系人
                    let mergedContact = try mergeContacts(contacts, policy: mergePolicy)
                    
                    
                    // 删除出去第一个的联系人(因为第一个的identifier就是mergedContact的identifier，直接更新这个主联系人就可以了)
                    for(index,item) in contacts.enumerated(){
                        if(index != 0){
                            saveRequest.delete(item.mutableCopy() as! CNMutableContact)
                        }
                    }
                    // 更新主（传入的第一个）联系人
                    saveRequest.update(mergedContact)
                    
                    mergedIDs.append(mergedContact.identifier)
                }
                
                try store.execute(saveRequest)
                DispatchQueue.main.async { completion(.success(mergedIDs)) }
                
            } catch let error as ContactMergeError {
                DispatchQueue.main.async { completion(.failure(error)) }
            } catch {
                DispatchQueue.main.async { completion(.failure(.systemError(error))) }
            }
        }
    }
    
    private static func fetchContacts(for group: [ContactModel], store: CNContactStore) throws -> [CNContact] {
        let identifiers = group.map { $0.identifier }
        let predicate = CNContact.predicateForContacts(withIdentifiers: identifiers)
        let keysToFetch: [CNKeyDescriptor] = [
            CNContactGivenNameKey, CNContactFamilyNameKey,
            CNContactPhoneNumbersKey, CNContactEmailAddressesKey,
            CNContactPostalAddressesKey, CNContactIdentifierKey
        ].map { $0 as CNKeyDescriptor }
        
        let contacts = try store.unifiedContacts(matching: predicate, keysToFetch: keysToFetch)
        
        // 验证所有联系人存在
        let foundIDs = Set(contacts.map { $0.identifier })
        guard let missing = identifiers.first(where: { !foundIDs.contains($0) }) else {
            return contacts
        }
        throw ContactMergeError.contactNotFound(identifier: missing)
    }
    
    private static func mergeContacts(_ contacts: [CNContact], policy: MergePolicy) throws -> CNMutableContact {
        guard let baseContact = contacts.first else { throw ContactMergeError.emptyGroup }
        
        let merged = baseContact.mutableCopy() as! CNMutableContact
        
        switch policy {
        case .union:
            for contact in contacts{
                mergePhoneNumbers(from: contact, to: merged)
                mergeEmails(from: contact, to: merged)
                mergeAddresses(from: contact, to: merged)
                mergeNames(from: contact, to: merged)
            }
            
        case .priority(let model):
            guard let priorityContact = contacts.first(where: { $0.identifier == model.identifier }) else {
                throw ContactMergeError.contactNotFound(identifier: model.identifier)
            }
            copyContactProperties(from: priorityContact, to: merged)
        }
        
        return merged
    }
    private static func mergePhoneNumbers(from source: CNContact, to target: CNMutableContact) {
        let existingNumbers = Set(target.phoneNumbers.map { $0.value.stringValue })
        let newNumbers = source.phoneNumbers.filter {
            !existingNumbers.contains($0.value.stringValue)
        }
        target.phoneNumbers.append(contentsOf: newNumbers)
    }
    
    private static func mergeEmails(from source: CNContact, to target: CNMutableContact) {
        let existingEmails = Set(target.emailAddresses.map { $0.value as String })
        let newEmails = source.emailAddresses.filter {
            !existingEmails.contains($0.value as String)
        }
        target.emailAddresses.append(contentsOf: newEmails)
    }
    
    private static func mergeAddresses(from source: CNContact, to target: CNMutableContact) {
        let existingAddresses = Set(target.postalAddresses.map { $0.value })
        let newAddresses = source.postalAddresses.filter {
            !existingAddresses.contains($0.value)
        }
        target.postalAddresses.append(contentsOf: newAddresses)
    }
    
    private static func mergeNames(from source: CNContact, to target: CNMutableContact) {
        // 保留非空字段
        if target.givenName.isEmpty && !source.givenName.isEmpty {
            target.givenName = source.givenName
        }
        if target.familyName.isEmpty && !source.familyName.isEmpty {
            target.familyName = source.familyName
        }
    }
    
    private static func copyContactProperties(from source: CNContact, to target: CNMutableContact) {
        // 基础信息
        target.givenName = source.givenName
        target.familyName = source.familyName
        target.middleName = source.middleName
        target.namePrefix = source.namePrefix
        target.nameSuffix = source.nameSuffix
        target.nickname = source.nickname
        
        // 组织信息
        target.organizationName = source.organizationName
        target.departmentName = source.departmentName
        target.jobTitle = source.jobTitle
        
        // 联系方式
        target.phoneNumbers = source.phoneNumbers.map {
            CNLabeledValue(label: $0.label, value: $0.value)
        }
        
        target.emailAddresses = source.emailAddresses.map {
            CNLabeledValue(label: $0.label, value: $0.value)
        }
        
        target.postalAddresses = source.postalAddresses.map {
            CNLabeledValue(label: $0.label, value: $0.value)
        }
        
        // 其他信息
        target.urlAddresses = source.urlAddresses.map {
            CNLabeledValue(label: $0.label, value: $0.value)
        }
        
        target.contactRelations = source.contactRelations.map {
            CNLabeledValue(label: $0.label, value: $0.value)
        }
        
        target.socialProfiles = source.socialProfiles.map {
            CNLabeledValue(label: $0.label, value: $0.value)
        }
        
        // 日期信息
        target.birthday = source.birthday
        target.dates = source.dates.map {
            CNLabeledValue(label: $0.label, value: $0.value)
        }
        
        // 备注
        target.note = source.note
    }
    
    // MARK: 导入联系人
    // 核心原子操作
    static func performAtomicRestore(_ contacts: [ContactModel], completion: @escaping (Bool, Error?) -> Void) {
        do {
            let contactStore = CNContactStore()
            // 1. 获取所有现有联系人ID
            let existingContactIDs = try ContactManager.getAllContactIDs()
            
            // 2. 创建统一事务请求
            let saveRequest = CNSaveRequest()
            
            // 3. 添加删除旧联系人的操作
            existingContactIDs.forEach { id in
                if let contact = try? contactStore.unifiedContact(withIdentifier: id, keysToFetch: [CNContactIdentifierKey as CNKeyDescriptor]) {
                    let mutableContact = contact.mutableCopy() as! CNMutableContact
                    saveRequest.delete(mutableContact)
                }
            }
            
            // 4. 添加新联系人
            for model in contacts {
                let newContact = ContactManager.createCNContact(from: model)
                saveRequest.add(newContact, toContainerWithIdentifier: nil)
            }
            
            // 5. 执行事务（原子性）
            try contactStore.execute(saveRequest)
            completion(true, nil)
        } catch {
            // 事务失败，所有操作自动回滚
            completion(false, error)
        }
    }
    
    private static func getAllContactIDs() throws -> [String] {
        let contactStore = CNContactStore()
        let request = CNContactFetchRequest(keysToFetch: [CNContactIdentifierKey as CNKeyDescriptor])
        var contactIDs = [String]()
        try contactStore.enumerateContacts(with: request) { contact, _ in
            contactIDs.append(contact.identifier)
        }
        return contactIDs
    }
    private static func createCNContact(from model: ContactModel) -> CNMutableContact {
        let contact = CNMutableContact()
        contact.givenName = model.givenName
        contact.familyName = model.familyName
        if let numbers = model.phoneNumber {
            contact.phoneNumbers = numbers.map { number in
                CNLabeledValue(label: CNLabelPhoneNumberMain, value: CNPhoneNumber(stringValue: number))
            }
        }
        return contact
    }
    
    // MARK: 根据id获取联系人
    static func fetchContactFromStore(model: ContactModel)->CNContact? {
        let contactStore = CNContactStore()
        // 指定需要获取的联系人字段（示例包含姓名和电话）
        let keysToFetch: [CNKeyDescriptor] = [
            CNContactIdentifierKey as CNKeyDescriptor,
            CNContactGivenNameKey as CNKeyDescriptor,
            CNContactFamilyNameKey as CNKeyDescriptor,
            CNContactPhoneNumbersKey as CNKeyDescriptor
        ]
        // 创建谓词（根据 identifier）
        let predicate = CNContact.predicateForContacts(withIdentifiers: [model.identifier])
        
        do {
            let contacts = try contactStore.unifiedContacts(matching: predicate, keysToFetch: keysToFetch)
            // 返回第一个匹配的联系人
            return contacts.first
        } catch {
            print("获取联系人失败：\(error)")
            return nil
        }
    }
    
    
    // MARK: 其他方法
    
    static func callContactWithIdentifier(_ model: ContactModel, viewController: UIViewController) {
        let editViewController = CustomContactViewController()
        editViewController.presentCustomContactEditor(with: model.identifier, viewController: viewController)
    }
    
}

