import Foundation
import Testing

@testable import NucleicCore

/// Contracts of the Covalence mesh diagnostics ring buffer (MeshDiagnostics.swift): monotonic row
/// identity, capacity trimming that keeps the newest rows, lifetime totals that survive both
/// trimming and `clear()`, and the timestamps the store injects via its `now` clock.
@MainActor
@Suite struct MeshDiagnosticsTests {
    @Test func recordsCarryMonotonicSeqAndFields() {
        let log = MeshDiagnosticsLog()
        let at = Date(timeIntervalSince1970: 1_000)
        let first = log.record(.peer, "peer connected: Studio", detail: "via LAN", at: at)
        let second = log.record(.dispatch, level: .warning, "no ack", at: at)

        #expect(first.seq < second.seq)
        #expect(log.events.map(\.id) == [first.seq, second.seq])
        #expect(first.category == .peer)
        #expect(first.level == .info)
        #expect(first.message == "peer connected: Studio")
        #expect(first.detail == "via LAN")
        #expect(first.at == at)
        #expect(second.level == .warning)
        #expect(second.detail == nil)
    }

    @Test func capacityTrimsOldestKeepsNewest() {
        let log = MeshDiagnosticsLog(capacity: 3)
        for i in 1...5 {
            log.record(.cast, "event \(i)")
        }
        #expect(log.events.count == 3)
        #expect(log.events.map(\.message) == ["event 3", "event 4", "event 5"])
        // Seq keeps counting across the trim — identities never recycle.
        #expect(log.events.last!.seq == 5)
        // Lifetime totals count what happened, not what's retained.
        #expect(log.totalsByCategory[.cast] == 5)
    }

    @Test func clearDropsRowsKeepsTotalsAndSeq() {
        let log = MeshDiagnosticsLog()
        log.record(.rebalance, "stays here")
        log.record(.transfer, level: .error, "failed")
        log.clear()

        #expect(log.events.isEmpty)
        #expect(log.totalsByCategory[.rebalance] == 1)
        #expect(log.totalsByCategory[.transfer] == 1)
        // Rows recorded after a clear continue the sequence — a viewer's stable ids stay stable.
        let next = log.record(.peer, "peer connected")
        #expect(next.seq == 3)
    }

    @Test func minimumCapacityIsOne() {
        let log = MeshDiagnosticsLog(capacity: 0)
        log.record(.peer, "a")
        log.record(.peer, "b")
        #expect(log.events.map(\.message) == ["b"])
    }
}
