AutoCat/AutoCatCore/Services/VehicleService/VehicleService.swift

165 lines
4.7 KiB
Swift

//
// VehicleService.swift
// AutoCatCore
//
// Created by Selim Mustafaev on 19.01.2025.
// Copyright © 2025 Selim Mustafaev. All rights reserved.
//
import Foundation
public typealias VehicleWithErrors = (
vehicle: VehicleDto,
errors: [Error]
)
public final class VehicleService {
let apiService: ApiServiceProtocol
let storageService: StorageServiceProtocol
let locationService: LocationServiceProtocol
public init(apiService: ApiServiceProtocol,
storageService: StorageServiceProtocol,
locationService: LocationServiceProtocol) {
self.apiService = apiService
self.storageService = storageService
self.locationService = locationService
}
}
extension VehicleService: VehicleServiceProtocol {
func check(
number: String,
numberType: VehicleNumberType,
forceUpdate: Bool,
trackLocation: Bool,
additionalEvent: VehicleEventDto?,
dbUpdatePolicy: DbUpdatePolicy
) async throws -> VehicleWithErrors {
var vehicle = switch numberType {
case .plateNumber:
(try? await storageService.loadVehicle(number: number)) ?? VehicleDto(number: number)
case .vin:
VehicleDto()
}
var errors: [Error] = []
let notes = vehicle.notes
let events: [VehicleEventDto]
if let additionalEvent, !vehicle.events.contains(where: { $0.id == additionalEvent.id }) {
events = vehicle.events + [additionalEvent]
} else {
events = vehicle.events
}
if additionalEvent != nil {
vehicle.events = events
vehicle.updatedDate = Date().timeIntervalSince1970
vehicle.synchronized = false
}
async let locationTask = trackLocation ? locationService.getRecentLocation() : nil
async let vehicleTask = apiService.checkVehicle(
by: number,
numberType: numberType,
notes: notes,
events: events,
force: forceUpdate
)
do {
vehicle = try await vehicleTask
} catch {
errors.append(error)
}
if trackLocation {
do {
if let event = try await locationTask {
vehicle.events.append(event)
vehicle.updatedDate = Date().timeIntervalSince1970
vehicle.synchronized = false
if !vehicle.unrecognized {
vehicle = try await apiService.add(event: event, to: number)
}
}
} catch {
errors.append(error)
}
}
await locationService.resetLastEvent()
if vehicle.plateNumberComplete {
try await storageService.updateVehicle(dto: vehicle, policy: dbUpdatePolicy)
}
return VehicleWithErrors(vehicle: vehicle, errors: errors)
}
public func check(number: String, numberType: VehicleNumberType, trackLocation: Bool) async throws -> VehicleWithErrors {
#if targetEnvironment(macCatalyst)
try await check(
number: number,
numberType: numberType,
forceUpdate: false,
trackLocation: false,
additionalEvent: nil,
dbUpdatePolicy: .always
)
#else
try await check(
number: number,
numberType: numberType,
forceUpdate: false,
trackLocation: trackLocation,
additionalEvent: nil,
dbUpdatePolicy: .always
)
#endif
}
public func updateHistory(number: String) async throws -> VehicleWithErrors {
try await check(
number: number,
numberType: .plateNumber,
forceUpdate: true,
trackLocation: false,
additionalEvent: nil,
dbUpdatePolicy: .always
)
}
public func updateSearch(number: String) async throws -> VehicleWithErrors {
try await check(
number: number,
numberType: .plateNumber,
forceUpdate: true,
trackLocation: false,
additionalEvent: nil,
dbUpdatePolicy: .ifExists
)
}
public func checkRecord(number: String, event: VehicleEventDto?) async throws -> VehicleWithErrors {
try await check(
number: number,
numberType: .plateNumber,
forceUpdate: false,
trackLocation: false,
additionalEvent: event,
dbUpdatePolicy: .always
)
}
}