import Foundation
import Testing
@testable import Notes

struct RelevanceTests {
    private let coffeeShop = (lat: 37.8044, lon: -122.2712)   // Oakland
    private let farAway = (lat: 40.7128, lon: -74.0060)       // NYC

    private func signals(
        lat: Double? = nil,
        lon: Double? = nil,
        place: String? = nil,
        createdAt: Date = Date(timeIntervalSinceNow: -7 * 86_400)
    ) -> RelevanceSignals {
        RelevanceSignals(
            latitude: lat, longitude: lon, placeName: place, locality: nil,
            createdAt: createdAt, timeZoneID: TimeZone.current.identifier
        )
    }

    @Test func nearbyNoteOutscoresFarNote() {
        let query = RelevanceQuery(latitude: coffeeShop.lat, longitude: coffeeShop.lon)
        let near = Relevance.score(signals(lat: coffeeShop.lat, lon: coffeeShop.lon), query: query)
        let far = Relevance.score(signals(lat: farAway.lat, lon: farAway.lon), query: query)
        #expect(near > far)
        #expect(near >= Relevance.surfacingThreshold)
    }

    @Test func farOldNoteStaysBelowThreshold() {
        let query = RelevanceQuery(latitude: coffeeShop.lat, longitude: coffeeShop.lon)
        let score = Relevance.score(
            signals(lat: farAway.lat, lon: farAway.lon, createdAt: Date(timeIntervalSinceNow: -180 * 86_400)),
            query: query
        )
        #expect(score < Relevance.surfacingThreshold)
    }

    @Test func samePlaceNameBoostsWithoutCoordinates() {
        var query = RelevanceQuery()
        query.placeName = "Blue Bottle Coffee"
        let matching = Relevance.score(signals(place: "blue bottle coffee"), query: query)
        let other = Relevance.score(signals(place: "Some Other Bar"), query: query)
        #expect(matching > other)
    }

    @Test func sameHourOutscoresOppositeHour() {
        let calendar = Calendar.current
        let now = Date()
        let sameHourYesterday = calendar.date(byAdding: .day, value: -1, to: now)!
        let twelveHoursOff = calendar.date(byAdding: .hour, value: -12, to: sameHourYesterday)!
        var query = RelevanceQuery()
        query.date = now
        let same = Relevance.score(signals(createdAt: sameHourYesterday), query: query)
        let opposite = Relevance.score(signals(createdAt: twelveHoursOff), query: query)
        #expect(same > opposite)
    }

    @Test func fresherNoteScoresHigher() {
        let query = RelevanceQuery()
        // Same clock time on different days isolates the recency term.
        let calendar = Calendar.current
        let recent = calendar.date(byAdding: .day, value: -7, to: query.date)!
        let old = calendar.date(byAdding: .day, value: -98, to: query.date)!
        let fresh = Relevance.score(signals(createdAt: recent), query: query)
        let stale = Relevance.score(signals(createdAt: old), query: query)
        #expect(fresh > stale)
    }
}
