//
//  MockServices.swift
//  SportsTimeTests
//
//  Mock implementations of services for testing. These mocks allow tests
//  to control service behavior and verify interactions.
//

import Foundation
import CoreLocation
@testable import SportsTime

// MARK: - Mock Data Provider

/// Mock data provider for testing components that depend on game/stadium/team data.
@MainActor
final class MockDataProvider {
    var games: [Game] = []
    var stadiums: [String: Stadium] = [:]
    var teams: [String: Team] = [:]

    var shouldFail = false
    var failureError: Error = NSError(domain: "MockError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Mock failure"])

    func configure(games: [Game], stadiums: [Stadium], teams: [Team]) {
        self.games = games
        self.stadiums = Dictionary(uniqueKeysWithValues: stadiums.map { ($0.id, $0) })
        self.teams = Dictionary(uniqueKeysWithValues: teams.map { ($0.id, $0) })
    }

    func stadium(for id: String) -> Stadium? {
        stadiums[id]
    }

    func team(for id: String) -> Team? {
        teams[id]
    }

    func filterGames(sports: Set<Sport>, startDate: Date, endDate: Date) throws -> [Game] {
        if shouldFail { throw failureError }
        return games.filter { game in
            sports.contains(game.sport) &&
            game.dateTime >= startDate &&
            game.dateTime <= endDate
        }
    }
}

// MARK: - Mock Location Service

/// Mock location service for testing distance and travel time calculations.
@MainActor
final class MockLocationService {
    var stubbedDistances: [String: Double] = [:]  // "from_to" -> meters
    var stubbedTravelTimes: [String: TimeInterval] = [:]  // "from_to" -> seconds
    var defaultDistanceMeters: Double = 100_000  // ~62 miles
    var defaultTravelTimeSeconds: TimeInterval = 3600  // 1 hour

    var shouldFail = false
    var failureError: Error = NSError(domain: "LocationError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Location unavailable"])

    var calculateDistanceCalls: [(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D)] = []
    var calculateTravelTimeCalls: [(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D)] = []

    func stubDistance(from: String, to: String, meters: Double) {
        stubbedDistances["\(from)_\(to)"] = meters
    }

    func stubTravelTime(from: String, to: String, seconds: TimeInterval) {
        stubbedTravelTimes["\(from)_\(to)"] = seconds
    }

    func calculateDistance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) async throws -> Double {
        calculateDistanceCalls.append((from: from, to: to))
        if shouldFail { throw failureError }
        return defaultDistanceMeters
    }

    func calculateTravelTime(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) async throws -> TimeInterval {
        calculateTravelTimeCalls.append((from: from, to: to))
        if shouldFail { throw failureError }
        return defaultTravelTimeSeconds
    }
}

// MARK: - Mock Route Service

/// Mock route service for testing route optimization.
@MainActor
final class MockRouteService {
    var shouldFail = false
    var failureError: Error = NSError(domain: "RouteError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Route unavailable"])

    var optimizeRouteCalls: [[CLLocationCoordinate2D]] = []
    var stubbedRoute: [Int]?  // Indices in order

    func optimizeRoute(waypoints: [CLLocationCoordinate2D]) async throws -> [Int] {
        optimizeRouteCalls.append(waypoints)
        if shouldFail { throw failureError }
        return stubbedRoute ?? Array(0..<waypoints.count)
    }
}
