import { createBatteriesResponse, createDashboardSnapshot } from '@/domain/battery' import { os } from '@/server/api/server' import { getBatteryHistory, getBatteryPredictionHistories, getLatestBatteryPage, getLatestBatteryPerDevice, } from '@/server/battery/mysql' import { isPredictionEnabled, predictSoh } from '@/server/prediction/client' const dashboardPredictionConcurrency = 5 async function mapWithConcurrency( items: T[], concurrency: number, handler: (item: T) => Promise, ): Promise { const results: R[] = [] let nextIndex = 0 async function worker() { while (nextIndex < items.length) { const index = nextIndex nextIndex += 1 const item = items[index] if (item !== undefined) results[index] = await handler(item) } } await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, worker)) return results } export const dashboard = os.battery.dashboard.handler(async () => { const items = await getLatestBatteryPerDevice() const predictionHistories = isPredictionEnabled() ? await getBatteryPredictionHistories(items.map((item) => item.mac)) : new Map() const predictionEntries = isPredictionEnabled() ? await mapWithConcurrency(items, dashboardPredictionConcurrency, async (item) => { const prediction = await predictSoh(item, predictionHistories.get(item.mac) ?? []) return prediction ? ([item.mac, prediction] as const) : null }) : [] const predictions = new Map(predictionEntries.filter((entry) => entry !== null)) return createDashboardSnapshot(items, new Date(), predictions) }) export const batteries = os.battery.batteries.handler(async ({ input }) => { const page = await getLatestBatteryPage(input) return createBatteriesResponse( page.items, new Date(), { total: page.total, lowPower: page.lowPower, charging: page.charging }, page.nextCursor, ) }) export const history = os.battery.history.handler(async ({ input }) => { const items = await getBatteryHistory(input.mac) return createBatteriesResponse(items) })