import Testing
import Foundation
@testable import nahbar

// MARK: - UserProfileStore Tests
//
// Testet die reine Logik des UserProfileStore (Initials, isEmpty, Persistenz).
// Nutzt einen isolierten UserDefaults-Key um Produktionsdaten nicht zu überschreiben.

@Suite("UserProfileStore – Initials")
struct UserProfileStoreInitialsTests {

    // Wir testen die Initialen-Logik isoliert, ohne den Store zu instanziieren.
    // Die Logik ist: Vorname[0] + Nachname[0] aus split by " "
    // Bei einem Wort: prefix(2).uppercased()
    // Bei leerem String: "?"

    private func initials(from name: String) -> String {
        let parts = name.split(separator: " ")
        if parts.count >= 2 {
            return (parts[0].prefix(1) + parts[1].prefix(1)).uppercased()
        }
        return name.isEmpty ? "?" : String(name.prefix(2)).uppercased()
    }

    @Test("Initials aus Vor- und Nachname")
    func initialsFromFullName() {
        #expect(initials(from: "Max Mustermann") == "MM")
    }

    @Test("Initials aus drei Wörtern")
    func initialsFromThreeWords() {
        #expect(initials(from: "Anna Maria Schmidt") == "AM")
    }

    @Test("Initials aus einem Wort (2 Buchstaben)")
    func initialsFromOneWord() {
        #expect(initials(from: "Max") == "MA")
    }

    @Test("Initials aus kurzem Namen (1 Buchstabe)")
    func initialsFromOneLetterName() {
        #expect(initials(from: "A") == "A")
    }

    @Test("Initials aus leerem String ist ?")
    func initialsFromEmptyStringIsQuestionMark() {
        #expect(initials(from: "") == "?")
    }

    @Test("Initials sind immer uppercase")
    func initialsAreAlwaysUppercase() {
        let names = ["anna bach", "max mustermann", "tim", ""]
        for name in names {
            let result = initials(from: name)
            #expect(result == result.uppercased(), "Initials für '\(name)' sollten uppercase sein")
        }
    }
}

// MARK: - UserProfileStore isEmpty Tests

@Suite("UserProfileStore – isEmpty")
struct UserProfileStoreIsEmptyTests {

    // isEmpty = name.isEmpty && displayName.isEmpty && occupation.isEmpty && location.isEmpty
    //           && likes.isEmpty && dislikes.isEmpty && socialStyle.isEmpty && gender.isEmpty

    private func isEmpty(name: String = "", displayName: String = "",
                         occupation: String = "", location: String = "",
                         likes: String = "", dislikes: String = "",
                         socialStyle: String = "", gender: String = "") -> Bool {
        name.isEmpty && displayName.isEmpty && occupation.isEmpty && location.isEmpty
            && likes.isEmpty && dislikes.isEmpty && socialStyle.isEmpty && gender.isEmpty
    }

    @Test("Alle Felder leer → isEmpty ist true")
    func allFieldsEmptyIsTrue() {
        #expect(isEmpty())
    }

    @Test("Nur Name gesetzt → isEmpty ist false")
    func onlyNameSetIsFalse() {
        #expect(!isEmpty(name: "Max"))
    }

    @Test("Nur displayName gesetzt → isEmpty ist false")
    func onlyDisplayNameSetIsFalse() {
        #expect(!isEmpty(displayName: "Maxi"))
    }

    @Test("Nur Beruf gesetzt → isEmpty ist false")
    func onlyOccupationSetIsFalse() {
        #expect(!isEmpty(occupation: "Ingenieur"))
    }

    @Test("Whitespace-only Name gilt als leer")
    func whitespaceNameIsEmpty() {
        // Der Store trimmt beim Speichern, also gilt "  " als leer
        #expect(isEmpty(name: ""))
    }

    @Test("Nur likes gesetzt → isEmpty ist false")
    func onlyLikesSetIsFalse() {
        #expect(!isEmpty(likes: "Kaffee, Sport"))
    }

    @Test("Nur dislikes gesetzt → isEmpty ist false")
    func onlyDislikesSetIsFalse() {
        #expect(!isEmpty(dislikes: "Lärm"))
    }

    @Test("Nur socialStyle gesetzt → isEmpty ist false")
    func onlySocialStyleSetIsFalse() {
        #expect(!isEmpty(socialStyle: "Introvertiert"))
    }

    @Test("Nur Geschlecht gesetzt → isEmpty ist false")
    func onlyGenderSetIsFalse() {
        #expect(!isEmpty(gender: "Weiblich"))
    }

    @Test("Alle Vorlieben-Felder leer + Rest leer → isEmpty ist true")
    func allVorliebFieldsEmptyStillEmpty() {
        #expect(isEmpty(likes: "", dislikes: "", socialStyle: "", gender: ""))
    }
}

// MARK: - UserProfileStore Neue Felder Tests

@Suite("UserProfileStore – Neue Felder")
struct UserProfileStoreNewFieldsTests {

    @Test("socialStyleOptions enthält genau 5 Einträge")
    func socialStyleOptionsCount() {
        let options = ["Introvertiert", "Eher introvertiert", "Ausgeglichen", "Eher extrovertiert", "Extrovertiert"]
        #expect(options.count == 5)
    }

    @Test("socialStyleOptions sind alle einzigartig")
    func socialStyleOptionsUnique() {
        let options = ["Introvertiert", "Eher introvertiert", "Ausgeglichen", "Eher extrovertiert", "Extrovertiert"]
        #expect(Set(options).count == options.count)
    }

    @Test("Likes-Parsing: Komma-getrennte Einträge werden korrekt aufgeteilt")
    func likesParsing() {
        let likes = "Kaffee, Sport, Natur"
        let items = likes.split(separator: ",").map { $0.trimmingCharacters(in: .whitespaces) }.filter { !$0.isEmpty }
        #expect(items == ["Kaffee", "Sport", "Natur"])
    }

    @Test("Likes-Parsing: Leerzeichen um Kommas werden getrimmt")
    func likesParsingTrimsWhitespace() {
        let likes = "  Kaffee  ,  Sport  "
        let items = likes.split(separator: ",").map { $0.trimmingCharacters(in: .whitespaces) }.filter { !$0.isEmpty }
        #expect(items == ["Kaffee", "Sport"])
    }

    @Test("Likes-Parsing: Leere Einträge werden gefiltert")
    func likesParsingFiltersEmpty() {
        let likes = "Kaffee,,Sport,"
        let items = likes.split(separator: ",").map { $0.trimmingCharacters(in: .whitespaces) }.filter { !$0.isEmpty }
        #expect(items == ["Kaffee", "Sport"])
    }

    @Test("Leerer Likes-String ergibt keine Einträge")
    func emptyLikesYieldsNoItems() {
        let items = "".split(separator: ",").map { $0.trimmingCharacters(in: .whitespaces) }.filter { !$0.isEmpty }
        #expect(items.isEmpty)
    }

    @Test("Geschlechtsoptionen enthalten Männlich, Weiblich, Divers")
    func genderOptionsContainExpectedValues() {
        let options = ["Männlich", "Weiblich", "Divers"]
        #expect(options.contains("Männlich"))
        #expect(options.contains("Weiblich"))
        #expect(options.contains("Divers"))
        #expect(options.count == 3)
    }

    @Test("Geschlechtsoptionen sind eindeutig")
    func genderOptionsUnique() {
        let options = ["Männlich", "Weiblich", "Divers"]
        #expect(Set(options).count == options.count)
    }
}

// MARK: - Vorname-Extraktion (Begrüßungslogik)

@Suite("TodayView – Vorname-Extraktion")
struct GreetingFirstNameTests {

    // Spiegelt die Logik aus TodayView.greeting wider:
    //   profileStore.name.split(separator: " ").first.map(String.init) ?? ""
    private func firstName(from name: String) -> String {
        name.split(separator: " ").first.map(String.init) ?? ""
    }

    @Test("Vorname aus vollem Namen")
    func firstNameFromFullName() {
        #expect(firstName(from: "Max Mustermann") == "Max")
    }

    @Test("Vorname aus dreiteiligem Namen")
    func firstNameFromThreeWordName() {
        #expect(firstName(from: "Anna Maria Schmidt") == "Anna")
    }

    @Test("Einzelner Name → dieser selbst als Vorname")
    func firstNameFromSingleWord() {
        #expect(firstName(from: "Max") == "Max")
    }

    @Test("Leerer Name → leerer Vorname")
    func firstNameFromEmptyString() {
        #expect(firstName(from: "").isEmpty)
    }

    @Test("Nur Leerzeichen → leerer Vorname")
    func firstNameFromWhitespaceOnly() {
        #expect(firstName(from: "   ").isEmpty)
    }

    @Test("Begrüßung mit Vorname enthält Komma und Punkt")
    func greetingFormatWithName() {
        let first = firstName(from: "Max Mustermann")
        let greeting = "Guten Tag, \(first)."
        #expect(greeting == "Guten Tag, Max.")
    }

    @Test("Begrüßung ohne Name endet mit Punkt (kein Komma)")
    func greetingFormatWithoutName() {
        let first = firstName(from: "")
        let greeting = first.isEmpty ? "Guten Tag." : "Guten Tag, \(first)."
        #expect(greeting == "Guten Tag.")
    }
}

// MARK: - Vorlieben-Nudge Anzeigelogik

@Suite("IchView – Vorlieben-Nudge Sichtbarkeit")
struct VorliebenNudgeTests {

    // Spiegelt die Bedingung in IchView.infoSection wider:
    // showNudge = likes.isEmpty && dislikes.isEmpty
    // showContent = !likes.isEmpty || !dislikes.isEmpty
    // infoSection nur sichtbar wenn !isEmpty (getrennt getestet)

    private func showNudge(likes: String, dislikes: String) -> Bool {
        likes.isEmpty && dislikes.isEmpty
    }

    @Test("Beide leer → Nudge wird angezeigt")
    func bothEmptyShowsNudge() {
        #expect(showNudge(likes: "", dislikes: ""))
    }

    @Test("Nur likes gesetzt → kein Nudge")
    func onlyLikesSetHidesNudge() {
        #expect(!showNudge(likes: "Kaffee", dislikes: ""))
    }

    @Test("Nur dislikes gesetzt → kein Nudge")
    func onlyDislikesSetHidesNudge() {
        #expect(!showNudge(likes: "", dislikes: "Lärm"))
    }

    @Test("Beide gesetzt → kein Nudge")
    func bothSetHidesNudge() {
        #expect(!showNudge(likes: "Kaffee", dislikes: "Lärm"))
    }

    @Test("Nudge und Content schließen sich gegenseitig aus")
    func nudgeAndContentAreMutuallyExclusive() {
        let cases: [(likes: String, dislikes: String)] = [
            ("", ""),
            ("Kaffee", ""),
            ("", "Lärm"),
            ("Kaffee", "Lärm"),
        ]
        for c in cases {
            let nudge   = showNudge(likes: c.likes, dislikes: c.dislikes)
            let content = !c.likes.isEmpty || !c.dislikes.isEmpty
            // Genau einer von beiden ist wahr, nie beide gleichzeitig
            #expect(nudge != content || (nudge == false && content == false),
                    "likes='\(c.likes)' dislikes='\(c.dislikes)': nudge=\(nudge) content=\(content)")
        }
    }

    @Test("Whitespace-only likes gilt als leer → Nudge erscheint (Store trimmt beim Speichern)")
    func whitespaceOnlyLikesCountsAsEmpty() {
        // Der Store trimmt Eingaben beim Speichern, daher landet nie reines Whitespace
        let trimmed = "   ".trimmingCharacters(in: .whitespaces)
        #expect(showNudge(likes: trimmed, dislikes: ""))
    }
}
