import Foundation
import Testing
@testable import IMessageSync

@Suite("SyncMessagePayload Serialization")
struct SyncPayloadTests {

    private func makePayload(service: String?) -> SyncMessagePayload {
        SyncMessagePayload(
            imessageGuid: "test-guid-001",
            senderId: nil,
            direction: "outgoing",
            sentAt: "2026-03-01T10:00:00Z",
            deliveredAt: nil,
            readAt: nil,
            text: "Hello",
            attributedBody: nil,
            associatedMessageType: nil,
            associatedMessageGuid: nil,
            isAudioMessage: false,
            expressiveSendStyleId: nil,
            replyToGuid: nil,
            threadOriginatorGuid: nil,
            groupTitle: nil,
            balloonBundleId: nil,
            service: service,
            senderIdentifier: nil,
            senderDisplayName: nil,
            senderPhoneNumber: nil,
            senderEmail: nil,
            attachments: [],
            attachmentsCount: 0,
            attachmentsTotalSize: 0,
            attachmentsFiletypes: []
        )
    }

    @Test func serviceFieldIncludedInDictionary() {
        let dict = makePayload(service: "iMessage").dictionary
        #expect(dict["service"] as? String == "iMessage")
    }

    @Test func smsServiceFieldSerializes() {
        let dict = makePayload(service: "SMS").dictionary
        #expect(dict["service"] as? String == "SMS")
    }

    @Test func nilServiceFieldOmittedFromDictionary() {
        // Nil optionals are dropped from the wire payload — the server uses
        // COALESCE semantics so absent ≡ "don't overwrite". Sending explicit
        // nulls would bloat every message payload for no signal.
        let dict = makePayload(service: nil).dictionary
        #expect(!dict.keys.contains("service"))
    }

    @Test func tapbackFieldsSerializeCorrectly() {
        let payload = SyncMessagePayload(
            imessageGuid: "tapback-guid-001",
            senderId: nil,
            direction: "outgoing",
            sentAt: "2026-03-01T10:01:00Z",
            deliveredAt: nil,
            readAt: nil,
            text: nil,
            attributedBody: nil,
            associatedMessageType: 2001,
            associatedMessageGuid: "p:0/parent-guid",
            isAudioMessage: false,
            expressiveSendStyleId: nil,
            replyToGuid: nil,
            threadOriginatorGuid: nil,
            groupTitle: nil,
            balloonBundleId: nil,
            service: "iMessage",
            senderIdentifier: nil,
            senderDisplayName: nil,
            senderPhoneNumber: nil,
            senderEmail: nil,
            attachments: [],
            attachmentsCount: 0,
            attachmentsTotalSize: 0,
            attachmentsFiletypes: []
        )
        let dict = payload.dictionary
        #expect(dict["associatedMessageType"] as? Int == 2001)
        #expect(dict["associatedMessageGuid"] as? String == "p:0/parent-guid")
        #expect(dict["service"] as? String == "iMessage")
    }
}

@Suite("iMessage Struct — Service Field")
struct iMessageServiceTests {

    @Test func iMessageStructHoldsServiceField() {
        let msg = iMessage(
            guid: "test-guid",
            conversationId: "conv-001",
            senderId: nil,
            isFromMe: true,
            date: Date(),
            dateDelivered: nil,
            dateRead: nil,
            text: "Hello",
            attributedBody: nil,
            associatedMessageType: nil,
            associatedMessageGuid: nil,
            isAudioMessage: false,
            expressiveSendStyleId: nil,
            replyToGuid: nil,
            threadOriginatorGuid: nil,
            groupTitle: nil,
            balloonBundleId: nil,
            service: "SMS",
            senderIdentifier: nil,
            senderDisplayName: nil,
            senderPhoneNumber: nil,
            senderEmail: nil,
            attachments: [],
            attachmentsCount: 0,
            attachmentsTotalSize: 0,
            attachmentsFiletypes: []
        )
        #expect(msg.service == "SMS")
    }

    @Test func iMessageStructAcceptsNilService() {
        let msg = iMessage(
            guid: "test-guid-nil",
            conversationId: "conv-001",
            senderId: nil,
            isFromMe: false,
            date: Date(),
            dateDelivered: nil,
            dateRead: nil,
            text: "Old message",
            attributedBody: nil,
            associatedMessageType: nil,
            associatedMessageGuid: nil,
            isAudioMessage: false,
            expressiveSendStyleId: nil,
            replyToGuid: nil,
            threadOriginatorGuid: nil,
            groupTitle: nil,
            balloonBundleId: nil,
            service: nil,
            senderIdentifier: nil,
            senderDisplayName: nil,
            senderPhoneNumber: nil,
            senderEmail: nil,
            attachments: [],
            attachmentsCount: 0,
            attachmentsTotalSize: 0,
            attachmentsFiletypes: []
        )
        #expect(msg.service == nil)
    }
}
