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

import SignalServiceKit

// MARK: - ProfileDetailLabel

public class ProfileDetailLabel: UIStackView {
    private let tapAction: (() -> Void)?
    private let longPressAction: (() -> Void)?

    public convenience init(
        title: String,
        icon: ThemeIcon,
        font: UIFont = .dynamicTypeBody,
        showDetailDisclosure: Bool = false,
        shouldLineWrap: Bool = true,
        tapAction: (() -> Void)? = nil,
        longPressAction: (() -> Void)? = nil
    ) {
        self.init(
            attributedTitle: NSMutableAttributedString(
                string: title,
                attributes: [
                    .font: font,
                    .foregroundColor: Theme.primaryTextColor,
                ]
            ),
            icon: icon,
            font: font,
            showDetailDisclosure: showDetailDisclosure,
            shouldLineWrap: shouldLineWrap,
            tapAction: tapAction,
            longPressAction: longPressAction
        )
    }

    public init(
        attributedTitle: NSAttributedString,
        icon: ThemeIcon,
        font: UIFont = .dynamicTypeBody,
        showDetailDisclosure: Bool = false,
        shouldLineWrap: Bool = true,
        tapAction: (() -> Void)? = nil,
        longPressAction: (() -> Void)? = nil
    ) {
        self.tapAction = tapAction
        self.longPressAction = longPressAction

        super.init(frame: .zero)
        self.axis = .horizontal
        self.spacing = 12
        self.alignment = .top
        self.layoutMargins = .zero

        // Make the icon an attributed string attachment so that it
        //  1. scales with Dynamic Type.
        //  2. is vertically centered with the first line of text
        //     when the stack view is horizontally aligned.
        let imageString = NSAttributedString.with(
            image: Theme.iconImage(icon),
            font: font,
            attributes: [
                .font: font,
                .foregroundColor: Theme.primaryTextColor,
            ]
        )
        let imageLabel = UILabel()
        self.addArrangedSubview(imageLabel)
        imageLabel.attributedText = imageString
        imageLabel.setCompressionResistanceHigh()

        let textLabel = UILabel()
        self.addArrangedSubview(textLabel)
        let titleString = NSMutableAttributedString(attributedString: attributedTitle)

        if
            showDetailDisclosure,
            let chevron = UIImage(named: "chevron-right-20")
        {
            let attachmentString = NSAttributedString.with(
                image: chevron,
                font: font,
                attributes: [.foregroundColor: Theme.primaryIconColor]
            )
            if shouldLineWrap {
                // Add the chevron at the end of the last line of text
                titleString.append(attachmentString)
            } else {
                // Add the chevron at the end of the truncated line
                let chevronLabel = UILabel()
                chevronLabel.attributedText = attachmentString
                chevronLabel.setCompressionResistanceHigh()
                self.addArrangedSubview(chevronLabel)
                self.addArrangedSubview(.hStretchingSpacer())
                self.setCustomSpacing(0, after: textLabel)
                self.setCustomSpacing(0, after: chevronLabel)
            }
        }
        textLabel.attributedText = titleString
        textLabel.textAlignment = .natural
        textLabel.numberOfLines = shouldLineWrap ? 0 : 1

        if tapAction != nil {
            addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(didTap)))
        }
        if longPressAction != nil {
            addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(didLongPress(sender:))))
        }
    }

    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    @objc
    private func didTap() {
        tapAction?()
    }

    @objc
    private func didLongPress(sender: UIGestureRecognizer) {
        guard sender.state == .began else { return }
        longPressAction?()
    }
}

// MARK: Convenience

public extension ProfileDetailLabel {
    static func profile(
        displayName: String,
        secondaryName: String? = nil,
        font: UIFont = .dynamicTypeBody,
        tapAction: (() -> Void)? = nil
    ) -> ProfileDetailLabel {
        .init(
            attributedTitle: {
                if let secondaryName {
                    return NSAttributedString.composed(of: [
                        displayName,
                        " ",
                        "(\(secondaryName))"
                            .styled(with: .color(Theme.secondaryTextAndIconColor))
                    ])
                } else {
                    return NSAttributedString.composed(of: [displayName])
                }
            }().styled(with: .font(font)),
            icon: .profileName,
            font: font,
            tapAction: tapAction
        )
    }

    static func verified(
        font: UIFont = .dynamicTypeBody
    ) -> ProfileDetailLabel {
        .init(title: SafetyNumberStrings.verified, icon: .checkmark, font: font)
    }

    static func profileAbout(
        bio: String,
        font: UIFont = .dynamicTypeBody
    ) -> ProfileDetailLabel {
        .init(title: bio, icon: .profileAbout, font: font)
    }

    static func signalConnectionLink(
        font: UIFont = .dynamicTypeBody,
        shouldDismissOnNavigation: Bool,
        presentEducationFrom viewController: UIViewController?
    ) -> ProfileDetailLabel {
        .init(
            title: OWSLocalizedString(
                "CONTACT_ABOUT_SHEET_SIGNAL_CONNECTION_LABEL",
                comment: "A label indicating a user is a signal connection."
            ),
            icon: .contactInfoSignalConnection,
            font: font,
            showDetailDisclosure: true,
            tapAction: { [weak viewController] in
                func action() {
                    viewController?.present(ConnectionsEducationSheetViewController(), animated: true)
                }
                if shouldDismissOnNavigation {
                    viewController?.dismiss(animated: true, completion: action)
                } else {
                    action()
                }
            }
        )
    }

    static func noDirectChat(
        name: String,
        font: UIFont = .dynamicTypeBody
    ) -> ProfileDetailLabel {
        .init(
            title: String(
                format: OWSLocalizedString(
                    "CONTACT_ABOUT_SHEET_NO_DIRECT_MESSAGES",
                    comment: "Indicates that the user has no messages with the other account. Embeds {{name}}"
                ),
                name
            ),
            icon: .contactInfoNoDirectChat,
            font: font
        )
    }

    static func blocked(
        name: String,
        font: UIFont = .dynamicTypeBody
    ) -> ProfileDetailLabel {
        .init(
            title: String(
                format: OWSLocalizedString(
                    "CONTACT_ABOUT_SHEET_BLOCKED_USER_FORMAT",
                    comment: "Indicates that the user has blocked the other account. Embeds {{name}}"
                ),
                name
            ),
            icon: .chatSettingsBlock,
            font: font
        )
    }

    static func pendingRequest(
        name: String,
        font: UIFont = .dynamicTypeBody
    ) -> ProfileDetailLabel {
        .init(
            title: OWSLocalizedString(
                "CONTACT_ABOUT_SHEET_PENDING_REQUEST",
                comment: "Indicates that the user has a pending request with the other account. Embeds {{name}}"
            ),
            icon: .contactInfoPendingRequest,
            font: font
        )
    }

    static func inSystemContacts(
        name: String,
        font: UIFont = .dynamicTypeBody
    ) -> ProfileDetailLabel {
        .init(
            title: String(
                format: OWSLocalizedString(
                    "CONTACT_ABOUT_SHEET_CONNECTION_IN_SYSTEM_CONTACTS",
                    comment: "Indicates that another account is in the user's system contacts. Embeds {{name}}"
                ),
                name
            ),
            icon: .contactInfoUserInContacts,
            font: font
        )
    }

    static func phoneNumber(
        _ phoneNumber: String,
        font: UIFont = .dynamicTypeBody,
        presentSuccessToastFrom viewController: UIViewController?
    ) -> ProfileDetailLabel {
        let copyPhoneNumber: () -> Void = { [weak viewController] in
            UIPasteboard.general.string = phoneNumber
            viewController?.presentToast(text: OWSLocalizedString(
                "COPIED_TO_CLIPBOARD",
                comment: "Indicator that a value has been copied to the clipboard."
            ))
        }
        let formattedPhoneNumber = PhoneNumber.bestEffortFormatPartialUserSpecifiedText(toLookLikeAPhoneNumber: phoneNumber)

        return .init(
            title: formattedPhoneNumber,
            icon: .contactInfoPhone,
            font: font,
            tapAction: copyPhoneNumber,
            longPressAction: copyPhoneNumber
        )
    }

    static func mutualGroups(
        for thread: TSThread,
        mutualGroups: [TSGroupThread],
        font: UIFont = .dynamicTypeBody
    ) -> ProfileDetailLabel {
        .init(
            title: mutualGroupsString(for: thread, mutualGroups: mutualGroups),
            icon: .contactInfoGroups,
            font: font
        )
    }

    static func note(
        _ noteText: String,
        font: UIFont = .dynamicTypeBody,
        onTap: () -> Void
    ) -> ProfileDetailLabel {
        .init(
            title: noteText,
            icon: .contactInfoNote
        )
    }

    static func mutualGroupsString(
        for thread: TSThread,
        mutualGroups: [TSGroupThread]
    ) -> String {
        switch (thread, mutualGroups.count) {
        case (_, 2...):
            let formatString = OWSLocalizedString(
                "MANY_GROUPS_IN_COMMON_%d", tableName: "PluralAware",
                comment: "A string describing that the user has many groups in common with another user. Embeds {{common group count}}")
            return String.localizedStringWithFormat(formatString, mutualGroups.count)

        case (is TSContactThread, 1):
            let formatString = OWSLocalizedString(
                "THREAD_DETAILS_ONE_MUTUAL_GROUP",
                comment: "A string indicating a mutual group the user shares with this contact. Embeds {{mutual group name}}")
            return String(format: formatString, mutualGroups[0].groupNameOrDefault)

        case (is TSGroupThread, 1):
            return OWSLocalizedString(
                "NO_OTHER_GROUPS_IN_COMMON",
                comment: "A string describing that the user has no groups in common other than the group implied by the current UI context")

        case (is TSContactThread, 0):
            return OWSLocalizedString(
                "NO_GROUPS_IN_COMMON",
                comment: "A string describing that the user has no groups in common with another user")

        default:
            owsFailDebug("Unexpected common group count")
            return ""
        }
    }
}
