//
// Copyright 2025 Element Creations Ltd.
// Copyright 2023-2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//

@testable import ElementX
import MatrixRustSDK
import Testing

struct RoomEventStringBuilderTests {
    private let ownUserID: String
    private let stringBuilder: RoomEventStringBuilder
    
    init() {
        ownUserID = "@alice:matrix.org"
        let stateEventStringBuilder = RoomStateEventStringBuilder(userID: ownUserID)
        let attributedStringBuilder = AttributedStringBuilder(mentionBuilder: MentionBuilder())
        
        stringBuilder = RoomEventStringBuilder(stateEventStringBuilder: stateEventStringBuilder,
                                               messageEventStringBuilder: RoomMessageEventStringBuilder(attributedStringBuilder: attributedStringBuilder,
                                                                                                        destination: .roomList),
                                               shouldDisambiguateDisplayNames: true,
                                               shouldPrefixSenderName: true)
    }
    
    @Test
    func senderPrefix() {
        let ownMessageString = stringBuilder.buildAttributedString(for: makeMessageItem(senderID: ownUserID, senderDisplayName: "Alice"))
        #expect(ownMessageString?.string == "You: Hello, World!", "Your own messages should be prefixed with 'You'")
        
        let otherMessageString = stringBuilder.buildAttributedString(for: makeMessageItem(senderID: "@bob:matrix.org", senderDisplayName: "Bob"))
        #expect(otherMessageString?.string == "Bob: Hello, World!", "Everyone else's messages should be prefixed with their display name.")
        
        let ambiguousMessageString = stringBuilder.buildAttributedString(for: makeMessageItem(senderID: "@charlie:matrix.org",
                                                                                              senderDisplayName: "Charlie",
                                                                                              senderDisplayNameAmbiguous: true))
        #expect(ambiguousMessageString?.string == "Charlie (@charlie:matrix.org): Hello, World!",
                "Messages from senders with ambiguous display names should include their user ID in the prefix.")
        
        let ownEmoteString = stringBuilder.buildAttributedString(for: makeMessageItem(senderID: ownUserID,
                                                                                      senderDisplayName: "Alice",
                                                                                      type: .emote,
                                                                                      message: "laughs"))
        #expect(ownEmoteString?.string == "* Alice laughs", "Your own emotes shouldn't contain 'You'")
        
        let otherEmoteString = stringBuilder.buildAttributedString(for: makeMessageItem(senderID: "@bob:matrix.org",
                                                                                        senderDisplayName: "Bob",
                                                                                        type: .emote,
                                                                                        message: "sighs"))
        #expect(otherEmoteString?.string == "* Bob sighs", "Everyone else's emotes should contain their display name.")
        
        let ownPollString = stringBuilder.buildAttributedString(for: makePollItem(senderID: ownUserID, senderDisplayName: "Alice"))
        #expect(ownPollString?.string == "You: Poll: Which is better?", "Your own polls should be prefixed with 'You'")
        
        let otherPollString = stringBuilder.buildAttributedString(for: makePollItem(senderID: "@bob:matrix.org", senderDisplayName: "Bob"))
        #expect(otherPollString?.string == "Bob: Poll: Which is better?", "Everyone else's polls should be prefixed with their display name.")
    }
    
    // MARK: - Helpers
    
    private enum MockMessageType { case textMessage, emote }
    
    private func makeMessageItem(senderID: String,
                                 senderDisplayName: String? = nil,
                                 senderDisplayNameAmbiguous: Bool = false,
                                 type: MockMessageType = .textMessage,
                                 message: String = "Hello, World!") -> EventTimelineItemProxy {
        let content = switch type {
        case .textMessage: makeTextContent(message: message)
        case .emote: makeEmoteContent(message: message)
        }
        
        return .init(item: .init(configuration: .init(eventID: "1234",
                                                      sender: senderID,
                                                      senderProfile: .ready(displayName: senderDisplayName, displayNameAmbiguous: senderDisplayNameAmbiguous, avatarUrl: nil),
                                                      isOwn: senderID == ownUserID,
                                                      content: .msgLike(content: .init(kind: .message(content: .init(msgType: content,
                                                                                                                     body: message,
                                                                                                                     isEdited: false,
                                                                                                                     mentions: nil)),
                                                                                       reactions: [],
                                                                                       inReplyTo: nil,
                                                                                       threadRoot: nil,
                                                                                       threadSummary: nil)))),
                     uniqueID: .init("0"))
    }
    
    private func makeTextContent(message: String) -> MessageType {
        .text(content: .init(body: message, formatted: nil))
    }
    
    private func makeEmoteContent(message: String) -> MessageType {
        .emote(content: .init(body: message, formatted: nil))
    }
    
    private func makePollItem(senderID: String,
                              senderDisplayName: String? = nil,
                              senderDisplayNameAmbiguous: Bool = false,
                              question: String = "Which is better?") -> EventTimelineItemProxy {
        .init(item: .init(configuration: .init(eventID: "1234",
                                               sender: senderID,
                                               senderProfile: .ready(displayName: senderDisplayName, displayNameAmbiguous: senderDisplayNameAmbiguous, avatarUrl: nil),
                                               isOwn: senderID == ownUserID,
                                               content: .msgLike(content: .init(kind: .poll(question: question,
                                                                                            kind: .disclosed,
                                                                                            maxSelections: 1,
                                                                                            answers: [],
                                                                                            votes: [:],
                                                                                            endTime: nil,
                                                                                            hasBeenEdited: false),
                                                                                reactions: [],
                                                                                inReplyTo: nil,
                                                                                threadRoot: nil,
                                                                                threadSummary: nil)))),
              uniqueID: .init("0"))
    }
}
