//
//  Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//

import Foundation

@objc
public class ContactShareViewModel: NSObject {

    @objc
    public let dbRecord: OWSContact

    @objc
    public var avatarImageData: Data? {
        didSet {
            self.cachedAvatarImage = nil
        }
    }

    private var cachedAvatarImage: UIImage?

    @objc
    public var avatarImage: UIImage? {
        if self.cachedAvatarImage != nil {
            return self.cachedAvatarImage
        }

        guard let avatarImageData = self.avatarImageData else {
            return nil
        }

        self.cachedAvatarImage = UIImage(data: avatarImageData)
        return cachedAvatarImage
    }

    @objc
    public required init(contactShareRecord: OWSContact, avatarImageData: Data?) {
        self.dbRecord = contactShareRecord
        self.avatarImageData = avatarImageData
    }

    @objc
    public convenience init(contactShareRecord: OWSContact, transaction: YapDatabaseReadTransaction) {
        if let avatarAttachment = contactShareRecord.avatarAttachment(with: transaction) as? TSAttachmentStream {
            self.init(contactShareRecord: contactShareRecord, avatarImageData: avatarAttachment.validStillImageData())
        } else {
            self.init(contactShareRecord: contactShareRecord, avatarImageData: nil)
        }
    }

    @objc
    public func getAvatarImage(diameter: CGFloat, contactsManager: OWSContactsManager) -> UIImage {
        if let avatarImage = avatarImage {
            return avatarImage
        }

        var colorSeed = name.displayName
        let recipientIds = systemContactsWithSignalAccountPhoneNumbers(contactsManager)
        if let firstRecipientId = recipientIds.first {
            // Try to use the first signal id as the default
            // avatar's color seed, so that it is as consistent
            // as possible with the user's avatar in other views.
            colorSeed = firstRecipientId
        }

        let avatarBuilder = OWSContactAvatarBuilder(nonSignalName: displayName,
                                                    colorSeed: colorSeed,
                                                    diameter: UInt(diameter),
                                                    contactsManager: contactsManager)
        // Note: we use buildDefaultImage() and not build() so that contact
        // share views always reflect the contents of the contact share.
        // build() might return an avatar from a corresponding system
        // contact or profile.  This could mislead the user into thinking
        // that an avatar they did not share was in fact included in the
        // contact share.
        return avatarBuilder.buildDefaultImage()
    }

    // MARK: Delegated -> dbRecord

    @objc
    public var name: OWSContactName {
        get {
            return dbRecord.name
        }
        set {
            return dbRecord.name = newValue
        }
    }

    @objc
    public var addresses: [OWSContactAddress] {
        get {
            return dbRecord.addresses
        }
        set {
            return dbRecord.addresses = newValue
        }
    }

    @objc
    public var emails: [OWSContactEmail] {
        get {
            return dbRecord.emails
        }
        set {
            dbRecord.emails = newValue
        }
    }

    @objc
    public var phoneNumbers: [OWSContactPhoneNumber] {
        get {
            return dbRecord.phoneNumbers
        }
        set {
            dbRecord.phoneNumbers = newValue
        }
    }

    @objc
    public func systemContactsWithSignalAccountPhoneNumbers(_ contactsManager: ContactsManagerProtocol) -> [String] {
        return dbRecord.systemContactsWithSignalAccountPhoneNumbers(contactsManager)
    }

    @objc
    public func systemContactPhoneNumbers(_ contactsManager: ContactsManagerProtocol) -> [String] {
        return dbRecord.systemContactPhoneNumbers(contactsManager)
    }

    @objc
    public func e164PhoneNumbers() -> [String] {
        return dbRecord.e164PhoneNumbers()
    }

    @objc
    public var displayName: String {
        return dbRecord.name.displayName
    }

    @objc
    public var ows_isValid: Bool {
        return dbRecord.ows_isValid()
    }

    @objc
    public var isProfileAvatar: Bool {
        return dbRecord.isProfileAvatar
    }

    @objc
    public func cnContact(mergedWithExistingContact existingContact: Contact) -> CNContact? {

        guard let newCNContact = OWSContacts.systemContact(for: self.dbRecord, imageData: self.avatarImageData) else {
            owsFail("\(logTag) in \(#function) newCNContact was unexpectedly nil")
            return nil
        }

        return existingContact.buildCNContact(mergedWithNewContact: newCNContact)
    }

    @objc
    public func copy(withName name: OWSContactName) -> ContactShareViewModel {

        // TODO move the `copy` logic into the view model?
        let newDbRecord = dbRecord.copy(with: name)

        return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImageData: self.avatarImageData)
    }

    @objc
    public func newContact(withName name: OWSContactName) -> ContactShareViewModel {

        // TODO move the `newContact` logic into the view model?
        let newDbRecord = dbRecord.newContact(with: name)

        // If we want to keep the avatar image, the caller will need to re-apply it.
        return ContactShareViewModel(contactShareRecord: newDbRecord, avatarImageData: nil)
    }

}