//
//  MessageCodableTests.swift
//  oAITests
//
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Copyright (C) 2026 Rune Olsen

import Testing
import Foundation
@testable import Confab

@Suite("Message Codable + Equatable")
struct MessageCodableTests {

    @Test("Transient fields don't survive an encode/decode round-trip")
    func transientFieldsDoNotPersist() throws {
        var message = Message(role: .assistant, content: "hi", isStreaming: true, generatedImages: [Data([0x01])])
        message.isStarred = true
        message.toolCalls = [ToolCallDetail(name: "test_tool", input: "{}", result: nil)]
        message.thinkingContent = "reasoning..."

        let data = try JSONEncoder().encode(message)
        let decoded = try JSONDecoder().decode(Message.self, from: data)

        #expect(decoded.content == "hi")
        #expect(decoded.isStreaming == false)
        #expect(decoded.isStarred == false)
        #expect(decoded.generatedImages == nil)
        #expect(decoded.toolCalls == nil)
        #expect(decoded.thinkingContent == nil)
    }

    @Test("Persisted fields survive an encode/decode round-trip")
    func persistedFieldsSurvive() throws {
        let message = Message(
            role: .user,
            content: "what's the weather",
            tokens: 42,
            cost: 0.0012,
            responseTime: 1.5,
            wasInterrupted: true,
            modelId: "claude-sonnet-5"
        )
        let data = try JSONEncoder().encode(message)
        let decoded = try JSONDecoder().decode(Message.self, from: data)

        #expect(decoded.id == message.id)
        #expect(decoded.role == message.role)
        #expect(decoded.content == message.content)
        #expect(decoded.tokens == message.tokens)
        #expect(decoded.cost == message.cost)
        #expect(decoded.responseTime == message.responseTime)
        #expect(decoded.wasInterrupted == message.wasInterrupted)
        #expect(decoded.modelId == message.modelId)
    }

    @Test("Custom == ignores role, timestamp, attachments, and modelId")
    func equalityIgnoresSomeFields() {
        let base = Message(id: UUID(), role: .user, content: "same", timestamp: Date())
        let differentRoleAndModel = Message(
            id: base.id,
            role: .assistant,
            content: "same",
            timestamp: Date(timeIntervalSince1970: 0),
            modelId: "some-other-model"
        )
        // Documents actual current behavior: these fields are intentionally
        // excluded from Message's custom == -- surprising if you don't know it.
        #expect(base == differentRoleAndModel)
    }

    @Test("Custom == does distinguish on content")
    func equalityDistinguishesContent() {
        let a = Message(id: UUID(), role: .user, content: "one")
        let b = Message(id: a.id, role: .user, content: "two")
        #expect(a != b)
    }

    @Test("FileAttachment.typeFromExtension recognizes common types")
    func attachmentTypeFromExtension() {
        #expect(FileAttachment.typeFromExtension("photo.PNG") == .image)
        #expect(FileAttachment.typeFromExtension("photo.jpg") == .image)
        #expect(FileAttachment.typeFromExtension("doc.pdf") == .pdf)
        #expect(FileAttachment.typeFromExtension("notes.md") == .text)
        #expect(FileAttachment.typeFromExtension("noextension") == .text)
    }

    @Test("FileAttachment.mimeType matches the detected extension")
    func attachmentMimeType() {
        let attachment = FileAttachment(path: "image.webp", type: .image, data: nil)
        #expect(attachment.mimeType == "image/webp")
    }
}
