import Testing
import Foundation
import SwiftData
@testable import nahbar

// MARK: - AppEventLog Tests
//
// Testet den In-Memory-Ring-Buffer und den Export.
// AppEventLog.shared ist ein Singleton – Tests sollten den Zustand
// am Ende nicht hinterlassen (wir testen nur lesende Operationen auf
// Entry-Strukturen, nicht auf dem geteilten Singleton).

@Suite("AppEventLog – Entry-Struktur")
struct AppEventLogEntryTests {

    @Test("Entry Level priority ist aufsteigend geordnet")
    func entryLevelPriorityIsAscending() {
        let levels = AppEventLog.Entry.Level.allCases
        for i in 1..<levels.count {
            #expect(levels[i].priority > levels[i-1].priority,
                    "Level \(levels[i]) sollte höhere Priorität als \(levels[i-1]) haben")
        }
    }

    @Test("Alle Levels haben ein nicht-leeres emoji")
    func allLevelsHaveEmoji() {
        for level in AppEventLog.Entry.Level.allCases {
            #expect(!level.emoji.isEmpty)
        }
    }

    @Test("Alle Levels haben ein nicht-leeres rawValue")
    func allLevelsHaveRawValue() {
        for level in AppEventLog.Entry.Level.allCases {
            #expect(!level.rawValue.isEmpty)
        }
    }

    @Test("Entry hat korrekte Felder nach Erstellung")
    func entryHasCorrectFieldsAfterCreation() {
        let before = Date()
        let entry = AppEventLog.Entry(level: .warning, category: "Test", message: "Testnachricht")
        let after = Date()

        #expect(entry.level == .warning)
        #expect(entry.category == "Test")
        #expect(entry.message == "Testnachricht")
        #expect(entry.timestamp >= before)
        #expect(entry.timestamp <= after)
        #expect(!entry.id.uuidString.isEmpty)
    }

    @Test("formattedTimestamp hat Format HH:mm:ss")
    func formattedTimestampHasCorrectFormat() {
        let entry = AppEventLog.Entry(level: .info, category: "Test", message: "Test")
        let ts = entry.formattedTimestamp
        // Format: HH:mm:ss → 8 Zeichen mit 2 Doppelpunkten
        #expect(ts.count == 8)
        #expect(ts.filter { $0 == ":" }.count == 2)
    }

    @Test("info hat niedrigste Priorität, critical die höchste")
    func infoPriorityIsLowestCriticalIsHighest() {
        #expect(AppEventLog.Entry.Level.info.priority < AppEventLog.Entry.Level.critical.priority)
    }

    @Test("warning hat höhere Priorität als info")
    func warningHasHigherPriorityThanInfo() {
        #expect(AppEventLog.Entry.Level.warning.priority > AppEventLog.Entry.Level.info.priority)
    }

    @Test("error hat höhere Priorität als warning")
    func errorHasHigherPriorityThanWarning() {
        #expect(AppEventLog.Entry.Level.error.priority > AppEventLog.Entry.Level.warning.priority)
    }
}

// MARK: - AppEventLog Export Tests

@Suite("AppEventLog – Export")
struct AppEventLogExportTests {

    @Test("exportText enthält Header-Bereiche")
    @MainActor
    func exportTextContainsHeaderSections() {
        let log = AppEventLog.shared
        let exported = log.exportText()

        #expect(exported.contains("nahbar App-Log"))
        #expect(exported.contains("Exportiert:"))
        #expect(exported.contains("Version:"))
        #expect(exported.contains("Gerät:"))
        #expect(exported.contains("Einträge:"))
    }

    @Test("exportText enthält mindestens einen Eintrag")
    @MainActor
    func exportTextContainsAtLeastOneEntry() {
        let log = AppEventLog.shared
        // Der shared-Log hat immer mindestens den Startup-Eintrag
        #expect(log.entries.count >= 1)
        let exported = log.exportText()
        #expect(!exported.isEmpty)
    }

    @Test("entries(minLevel:) filtert korrekt")
    @MainActor
    func entriesFiltersByMinLevel() {
        let log = AppEventLog.shared

        // Alle Einträge >= warning sollten keine INFO-Einträge enthalten
        let warningAndAbove = log.entries(minLevel: .warning)
        for entry in warningAndAbove {
            #expect(entry.level.priority >= AppEventLog.Entry.Level.warning.priority)
        }
    }
}

// MARK: - LogExportDocument Tests

@Suite("LogExportDocument – Transferable")
struct LogExportDocumentTests {

    @Test("LogExportDocument speichert Text korrekt")
    func documentStoresTextCorrectly() {
        let text = "Test Log Content\nLine 2"
        let doc = LogExportDocument(text: text)
        #expect(doc.text == text)
    }
}

// MARK: - Regressions-Wächter: Schema-Versionen

@Suite("Schema – Regressionswächter")
struct SchemaRegressionTests {

    @Test("NahbarSchemaV1 hat Version 1.0.0")
    func schemaV1HasCorrectVersion() {
        #expect(NahbarSchemaV1.versionIdentifier.major == 1)
        #expect(NahbarSchemaV1.versionIdentifier.minor == 0)
        #expect(NahbarSchemaV1.versionIdentifier.patch == 0)
    }

    @Test("NahbarSchemaV2 hat Version 2.0.0")
    func schemaV2HasCorrectVersion() {
        #expect(NahbarSchemaV2.versionIdentifier.major == 2)
        #expect(NahbarSchemaV2.versionIdentifier.minor == 0)
        #expect(NahbarSchemaV2.versionIdentifier.patch == 0)
    }

    @Test("NahbarSchemaV3 hat Version 3.0.0")
    func schemaV3HasCorrectVersion() {
        #expect(NahbarSchemaV3.versionIdentifier.major == 3)
        #expect(NahbarSchemaV3.versionIdentifier.minor == 0)
        #expect(NahbarSchemaV3.versionIdentifier.patch == 0)
    }

    @Test("Migrationsplan enthält genau 9 Schemas (V1–V9)")
    func migrationPlanHasNineSchemas() {
        #expect(NahbarMigrationPlan.schemas.count == 9)
    }

    @Test("Migrationsplan enthält genau 8 Stages (V1→V2 bis V8→V9)")
    func migrationPlanHasEightStages() {
        #expect(NahbarMigrationPlan.stages.count == 8)
    }

    @Test("ContainerFallback-Gleichheit funktioniert korrekt")
    func containerFallbackEquality() {
        #expect(ContainerFallback.cloudKit == .cloudKit)
        #expect(ContainerFallback.localOnly == .localOnly)
        #expect(ContainerFallback.inMemory == .inMemory)
        #expect(ContainerFallback.cloudKit != .localOnly)
    }
}
