//
//  HistoricalGameScraperTests.swift
//  SportsTimeTests
//
//  TDD specification tests for HistoricalGameScraper types.
//

import Testing
import Foundation
@testable import SportsTime

// MARK: - ScrapedGame Tests

@Suite("ScrapedGame")
struct ScrapedGameTests {

    // MARK: - Test Data

    private func makeGame(
        homeTeam: String = "Yankees",
        awayTeam: String = "Red Sox",
        homeScore: Int? = 5,
        awayScore: Int? = 3,
        stadiumName: String = "Yankee Stadium",
        sport: Sport = .mlb
    ) -> ScrapedGame {
        ScrapedGame(
            date: Date(),
            homeTeam: homeTeam,
            awayTeam: awayTeam,
            homeScore: homeScore,
            awayScore: awayScore,
            stadiumName: stadiumName,
            sport: sport
        )
    }

    // MARK: - Specification Tests: formattedScore

    /// - Expected Behavior: Format is "awayTeam awayScore - homeTeam homeScore"
    @Test("formattedScore: formats as 'away score - home score'")
    func formattedScore_format() {
        let game = makeGame(homeTeam: "Yankees", awayTeam: "Red Sox", homeScore: 5, awayScore: 3)
        #expect(game.formattedScore == "Red Sox 3 - Yankees 5")
    }

    /// - Expected Behavior: nil when homeScore is nil
    @Test("formattedScore: nil when homeScore nil")
    func formattedScore_nilHomeScore() {
        let game = makeGame(homeScore: nil, awayScore: 3)
        #expect(game.formattedScore == nil)
    }

    /// - Expected Behavior: nil when awayScore is nil
    @Test("formattedScore: nil when awayScore nil")
    func formattedScore_nilAwayScore() {
        let game = makeGame(homeScore: 5, awayScore: nil)
        #expect(game.formattedScore == nil)
    }

    /// - Expected Behavior: nil when both scores are nil
    @Test("formattedScore: nil when both scores nil")
    func formattedScore_bothNil() {
        let game = makeGame(homeScore: nil, awayScore: nil)
        #expect(game.formattedScore == nil)
    }

    // MARK: - Specification Tests: Properties

    @Test("ScrapedGame: stores date")
    func scrapedGame_date() {
        let date = Date()
        let game = ScrapedGame(
            date: date,
            homeTeam: "Home",
            awayTeam: "Away",
            homeScore: 1,
            awayScore: 0,
            stadiumName: "Stadium",
            sport: .mlb
        )
        #expect(game.date == date)
    }

    @Test("ScrapedGame: stores homeTeam")
    func scrapedGame_homeTeam() {
        let game = makeGame(homeTeam: "Home Team")
        #expect(game.homeTeam == "Home Team")
    }

    @Test("ScrapedGame: stores awayTeam")
    func scrapedGame_awayTeam() {
        let game = makeGame(awayTeam: "Away Team")
        #expect(game.awayTeam == "Away Team")
    }

    @Test("ScrapedGame: stores stadiumName")
    func scrapedGame_stadiumName() {
        let game = makeGame(stadiumName: "Test Stadium")
        #expect(game.stadiumName == "Test Stadium")
    }

    @Test("ScrapedGame: stores sport")
    func scrapedGame_sport() {
        let game = makeGame(sport: .nba)
        #expect(game.sport == .nba)
    }

    // MARK: - Edge Cases

    @Test("formattedScore: handles zero scores")
    func formattedScore_zeroScores() {
        let game = makeGame(homeScore: 0, awayScore: 0)
        #expect(game.formattedScore == "Red Sox 0 - Yankees 0")
    }

    @Test("formattedScore: handles high scores")
    func formattedScore_highScores() {
        let game = makeGame(homeScore: 123, awayScore: 456)
        #expect(game.formattedScore == "Red Sox 456 - Yankees 123")
    }

    // MARK: - Invariant Tests

    /// - Invariant: formattedScore != nil implies both scores are present
    @Test("Invariant: formattedScore implies both scores present")
    func invariant_formattedScoreImpliesBothScores() {
        let withScore = makeGame(homeScore: 5, awayScore: 3)
        if withScore.formattedScore != nil {
            #expect(withScore.homeScore != nil)
            #expect(withScore.awayScore != nil)
        }
    }

    /// - Invariant: formattedScore == nil implies at least one score is nil
    @Test("Invariant: nil formattedScore implies missing score")
    func invariant_nilFormattedScoreImpliesMissingScore() {
        let testCases: [(homeScore: Int?, awayScore: Int?)] = [
            (nil, 3),
            (5, nil),
            (nil, nil)
        ]

        for (home, away) in testCases {
            let game = makeGame(homeScore: home, awayScore: away)
            if game.formattedScore == nil {
                #expect(home == nil || away == nil)
            }
        }
    }
}
