import Foundation

/// The idle/browse surface only: wallet balance + nearby scooters.
///
/// The ride lifecycle deliberately does NOT live here  it belongs to `RideViewModel`,
/// which models it as an explicit state machine (ViewModels/RideFlow.swift).
@MainActor
final class HomeViewModel: ObservableObject {
    private let rides: RideRepository
    private let wallet: WalletRepository
    private let zones: ZoneRepository
    private let location: LocationProvider

    @Published private(set) var balance: WalletResponse?
    @Published private(set) var nearby: [NearbyScooter] = []
    @Published private(set) var parking: [ParkingSpot] = []
    @Published private(set) var loading = false
    @Published private(set) var error: String?

    /// Where the last refresh searched from, so the map can centre on the same point.
    @Published private(set) var origin = LocationProvider.fallback

    init(
        rides: RideRepository,
        wallet: WalletRepository,
        zones: ZoneRepository,
        location: LocationProvider
    ) {
        self.rides = rides
        self.wallet = wallet
        self.zones = zones
        self.location = location
    }

    /// Reload the map.
    ///
    /// - Parameter silent: true for the periodic poll: it must not flash the loading strip or
    ///   clear a visible error every few seconds. Only a refresh the rider asked for does that.
    func refresh(silent: Bool = false) {
        if !silent {
            loading = true
            error = nil
        }
        Task {
            let here = await location.current()
            origin = here
            do {
                balance = try await wallet.balance()
                nearby = try await rides.nearby(lat: here.lat, lng: here.lng)
            } catch {
                self.error = (error as? LocalizedError)?.errorDescription ?? error.localizedDescription
            }
            loading = false
            // Parking is loaded separately and its failure is swallowed on purpose: not knowing
            // where the racks are should never turn the home screen into an error state when the
            // rider can still see and unlock scooters.
            parking = (try? await zones.parkingNearby(lat: here.lat, lng: here.lng)) ?? []
        }
    }
}
