//
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import Foundation
import SignalCoreKit

public extension TSInfoMessage {
    class func insertProfileChangeMessagesIfNecessary(
        oldProfile: OWSUserProfile,
        newProfile: OWSUserProfile,
        transaction: SDSAnyWriteTransaction
    ) {
        let address: SignalServiceAddress
        switch oldProfile.internalAddress {
        case .localUser:
            return
        case .otherUser(let otherUserAddress):
            address = otherUserAddress
        }

        let profileChanges = ProfileChanges(
            address: address,
            oldProfile: oldProfile,
            newProfile: newProfile
        )

        guard profileChanges.hasRenderableChanges else {
            return
        }

        func saveProfileUpdateMessage(thread: TSThread) {
            let profileUpdateMessage = TSInfoMessage(
                thread: thread,
                messageType: .profileUpdate,
                infoMessageUserInfo: [.profileChanges: profileChanges]
            )
            profileUpdateMessage.wasRead = true
            profileUpdateMessage.anyInsert(transaction: transaction)
        }

        let contactThread = TSContactThread.getOrCreateThread(withContactAddress: address, transaction: transaction)
        if contactThread.shouldThreadBeVisible {
            saveProfileUpdateMessage(thread: contactThread)
        }

        for groupThread in TSGroupThread.groupThreads(with: address, transaction: transaction) {
            guard groupThread.groupModel.groupMembership.isLocalUserFullMember && groupThread.shouldThreadBeVisible else {
                continue
            }
            saveProfileUpdateMessage(thread: groupThread)
        }
    }
}

@objcMembers
public class ProfileChanges: MTLModel {
    var address: SignalServiceAddress?

    var oldNameComponents: PersonNameComponents?
    var newNameComponents: PersonNameComponents?

    var oldFullName: String? {
        guard let oldNameComponents = oldNameComponents else { return nil }
        return OWSFormat.formatNameComponents(oldNameComponents).filterStringForDisplay()
    }

    var newFullName: String? {
        guard let newNameComponents = newNameComponents else { return nil }
        return OWSFormat.formatNameComponents(newNameComponents).filterStringForDisplay()
    }

    var hasRenderableChanges: Bool {
        return oldFullName != nil && newFullName != nil && oldFullName != newFullName
    }

    init(address: SignalServiceAddress, oldProfile: OWSUserProfile, newProfile: OWSUserProfile) {
        self.address = address
        self.oldNameComponents = oldProfile.filteredNameComponents
        self.newNameComponents = newProfile.filteredNameComponents

        // TODO: Eventually, we'll want to track profile
        // photo and username changes here too.

        super.init()
    }

    public override init!() {
        super.init()
    }

    required init!(coder: NSCoder!) {
        super.init(coder: coder)
    }

    required init(dictionary dictionaryValue: [String: Any]!) throws {
        try super.init(dictionary: dictionaryValue)
    }

    func descriptionForUpdate(transaction: SDSAnyReadTransaction) -> String? {
        guard let address = address else {
            owsFailDebug("Unexpectedly missing address for profile change")
            return nil
        }

        guard let oldFullName = oldFullName, let newFullName = newFullName else {
            owsFailDebug("Unexpectedly missing old and new full name")
            return nil
        }

        if let phoneNumber = address.phoneNumber, let systemContactName = contactsManager.systemContactName(for: phoneNumber, tx: transaction) {
            let formatString = OWSLocalizedString(
                "PROFILE_NAME_CHANGE_SYSTEM_CONTACT_FORMAT",
                comment: "The copy rendered in a conversation when someone in your address book changes their profile name. Embeds {contact name}, {old profile name}, {new profile name}"
            )
            return String(format: formatString, systemContactName.resolvedValue(), oldFullName, newFullName)
        } else {
            let formatString = OWSLocalizedString(
                "PROFILE_NAME_CHANGE_SYSTEM_NONCONTACT_FORMAT",
                comment: "The copy rendered in a conversation when someone not in your address book changes their profile name. Embeds {old profile name}, {new profile name}"
            )
            return String(format: formatString, oldFullName, newFullName)
        }
    }
}
