//
//  PDFAssetPrefetcher.swift
//  SportsTime
//
//  Orchestrates parallel prefetching of all assets needed for PDF generation.
//

import Foundation
import UIKit

actor PDFAssetPrefetcher {

    // MARK: - Types

    struct PrefetchedAssets {
        let routeMap: UIImage?
        let cityMaps: [String: UIImage]
        let teamLogos: [String: UIImage]
        let stadiumPhotos: [String: UIImage]
        let cityPOIs: [String: [POISearchService.POI]]

        var isEmpty: Bool {
            routeMap == nil && cityMaps.isEmpty && teamLogos.isEmpty && stadiumPhotos.isEmpty && cityPOIs.isEmpty
        }
    }

    struct PrefetchProgress {
        var routeMapComplete: Bool = false
        var cityMapsComplete: Bool = false
        var logosComplete: Bool = false
        var photosComplete: Bool = false
        var poisComplete: Bool = false

        var percentComplete: Double {
            let completedSteps = [routeMapComplete, cityMapsComplete, logosComplete, photosComplete, poisComplete]
                .filter { $0 }.count
            return Double(completedSteps) / 5.0
        }

        var currentStep: String {
            if !routeMapComplete { return "Generating route map..." }
            if !cityMapsComplete { return "Generating city maps..." }
            if !logosComplete { return "Downloading team logos..." }
            if !photosComplete { return "Downloading stadium photos..." }
            if !poisComplete { return "Finding nearby attractions..." }
            return "Complete"
        }
    }

    // MARK: - Properties

    private let mapService = MapSnapshotService()
    private let imageService = RemoteImageService()
    private let poiService = POISearchService()

    // MARK: - Public Methods

    /// Prefetch all assets needed for PDF generation
    /// - Parameters:
    ///   - trip: The trip to generate PDF for
    ///   - games: Map of game IDs to RichGame objects
    ///   - progressCallback: Optional callback for progress updates
    /// - Returns: All prefetched assets
    func prefetchAssets(
        for trip: Trip,
        games: [String: RichGame],
        progressCallback: ((PrefetchProgress) async -> Void)? = nil
    ) async -> PrefetchedAssets {
        var progress = PrefetchProgress()

        // Collect unique teams and stadiums from games
        var teams: [Team] = []
        var stadiums: [Stadium] = []
        var seenTeamIds: Set<String> = []
        var seenStadiumIds: Set<String> = []

        for (_, richGame) in games {
            if !seenTeamIds.contains(richGame.homeTeam.id) {
                teams.append(richGame.homeTeam)
                seenTeamIds.insert(richGame.homeTeam.id)
            }
            if !seenTeamIds.contains(richGame.awayTeam.id) {
                teams.append(richGame.awayTeam)
                seenTeamIds.insert(richGame.awayTeam.id)
            }
            if !seenStadiumIds.contains(richGame.stadium.id) {
                stadiums.append(richGame.stadium)
                seenStadiumIds.insert(richGame.stadium.id)
            }
        }

        // Create immutable copies for concurrent access
        let teamsToFetch = teams
        let stadiumsToFetch = stadiums

        // Run all fetches in parallel
        async let routeMapTask = fetchRouteMap(stops: trip.stops)
        async let cityMapsTask = fetchCityMaps(stops: trip.stops)
        async let logosTask = imageService.fetchTeamLogos(teams: teamsToFetch)
        async let photosTask = imageService.fetchStadiumPhotos(stadiums: stadiumsToFetch)
        async let poisTask = poiService.findPOIsForCities(stops: trip.stops, limit: 5)

        // Await each result and update progress
        let routeMap = await routeMapTask
        progress.routeMapComplete = true
        await progressCallback?(progress)

        let cityMaps = await cityMapsTask
        progress.cityMapsComplete = true
        await progressCallback?(progress)

        let teamLogos = await logosTask
        progress.logosComplete = true
        await progressCallback?(progress)

        let stadiumPhotos = await photosTask
        progress.photosComplete = true
        await progressCallback?(progress)

        let cityPOIs = await poisTask
        progress.poisComplete = true
        await progressCallback?(progress)

        return PrefetchedAssets(
            routeMap: routeMap,
            cityMaps: cityMaps,
            teamLogos: teamLogos,
            stadiumPhotos: stadiumPhotos,
            cityPOIs: cityPOIs
        )
    }

    // MARK: - Private Methods

    private func fetchRouteMap(stops: [TripStop]) async -> UIImage? {
        do {
            // PDF page is 612 wide, minus margins
            let mapSize = CGSize(width: 512, height: 350)
            return try await mapService.generateRouteMap(stops: stops, size: mapSize)
        } catch {
            return nil
        }
    }

    private func fetchCityMaps(stops: [TripStop]) async -> [String: UIImage] {
        var results: [String: UIImage] = [:]
        let mapSize = CGSize(width: 250, height: 200)

        await withTaskGroup(of: (String, UIImage?).self) { group in
            // Deduplicate cities
            var seenCities: Set<String> = []
            for stop in stops {
                guard !seenCities.contains(stop.city) else { continue }
                seenCities.insert(stop.city)

                group.addTask {
                    do {
                        let map = try await self.mapService.generateCityMap(stop: stop, size: mapSize)
                        return (stop.city, map)
                    } catch {
                        return (stop.city, nil)
                    }
                }
            }

            for await (city, map) in group {
                if let map = map {
                    results[city] = map
                }
            }
        }

        return results
    }
}
