import Foundation
import Testing

@testable import NucleicCore

@Suite("Omnisearch — query matching + keyword index")
struct OmnisearchTests {
    // MARK: SearchQuery

    @Test func emptyQueryMatchesEverything() {
        let q = SearchQuery("   ")
        #expect(q.isEmpty)
        #expect(q.matches("anything at all"))
        #expect(q.matches(""))
    }

    @Test func matchIsCaseInsensitiveSubstring() {
        let q = SearchQuery("Auth")
        #expect(!q.isEmpty)
        #expect(q.matches("Refactor authentication flow"))
        #expect(q.matches("AUTHORIZE"))
        #expect(!q.matches("login screen"))
    }

    @Test func multipleTokensAllMustMatch() {
        let q = SearchQuery("login button")
        // Both tokens present (order-independent, anywhere in the haystack).
        #expect(q.matches("Fix the button on the login page"))
        // Only one token present → no match.
        #expect(!q.matches("Fix the login page"))
        #expect(!q.matches("Style the submit button"))
    }

    // MARK: Heuristic keyword index

    @Test func keywordsLeadWithTitleTokensAndDropStopwords() {
        let keys = HeuristicSummary.keywords(
            title: "Fix the login button",
            digest: "The user asked to fix the button on the authentication screen")
        // Stopwords ("the", "fix" is kept — only connectives/short are dropped) gone; title
        // content words come first and short/stopword tokens are excluded.
        #expect(keys.contains("login"))
        #expect(keys.contains("button"))
        #expect(!keys.contains("the"))
        // "authentication" comes from the digest and should be indexed too.
        #expect(keys.contains("authentication"))
        // Deduped: "button" appears in both title and digest but only once.
        #expect(keys.filter { $0 == "button" }.count == 1)
    }

    @Test func keywordsAreCappedAndDeduped() {
        let digest = Array(repeating: "alpha bravo charlie delta echo foxtrot golf hotel india juliet kilo lima mike", count: 3)
            .joined(separator: " ")
        let keys = HeuristicSummary.keywords(title: "Zeta", digest: digest, limit: 5)
        #expect(keys.count == 5)
        #expect(keys.first == "zeta")  // title leads
        #expect(Set(keys).count == keys.count)  // no dupes
    }

    @Test func heuristicProviderReturnsKeywordsByDefault() async {
        // The dependency-free provider's default keyword extraction returns the title's tokens,
        // so search still works with Intelligence off.
        let keys = await HeuristicIntelligence().sessionKeywords(
            title: "Refactor payment retries", digest: "")
        #expect(keys.contains("refactor"))
        #expect(keys.contains("payment"))
        #expect(keys.contains("retries"))
    }
}
