import { SpanStatusCode, trace } from "@opentelemetry/api"; import { currentAccessToken } from "../auth/oidc"; import type { WWIKpi, WWIReorderRecommendation, WWISupplierScore, WWIBusinessEvent, WWIWhatIfResult, WWIScenario, } from "./types"; const API_BASE = import.meta.env.VITE_API_BASE_URL ?? "http://localhost:8000"; const tracer = trace.getTracer("wwi-frontend-api"); function authHeaders(): Record { const token = currentAccessToken(); return token ? { Authorization: `Bearer ${token}` } : {}; } async function get(path: string, spanName: string): Promise { return tracer.startActiveSpan(spanName, async (span) => { try { const resp = await fetch(`${API_BASE}${path}`, { headers: { Accept: "application/json", ...authHeaders() }, }); if (!resp.ok) { const body = await resp.text(); throw new Error(`HTTP ${resp.status}: ${body}`); } span.setAttribute("http.status_code", resp.status); span.setStatus({ code: SpanStatusCode.OK }); return (await resp.json()) as T; } catch (err) { span.recordException(err as Error); span.setStatus({ code: SpanStatusCode.ERROR, message: String(err) }); throw err; } finally { span.end(); } }); } async function post(path: string, body: unknown, spanName: string): Promise { return tracer.startActiveSpan(spanName, async (span) => { try { const resp = await fetch(`${API_BASE}${path}`, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", ...authHeaders(), }, body: JSON.stringify(body), }); if (!resp.ok) { const text = await resp.text(); throw new Error(`HTTP ${resp.status}: ${text}`); } span.setAttribute("http.status_code", resp.status); span.setStatus({ code: SpanStatusCode.OK }); return (await resp.json()) as T; } catch (err) { span.recordException(err as Error); span.setStatus({ code: SpanStatusCode.ERROR, message: String(err) }); throw err; } finally { span.end(); } }); } export const getWWIKpis = () => get("/api/wwi/sales/kpis", "frontend.wwi.sales_kpis"); export const getWWIReorderRecommendations = () => get( "/api/wwi/stock/recommendations", "frontend.wwi.reorder_recommendations", ); export const getWWISupplierScores = (topN = 10) => get( `/api/wwi/suppliers/scores?top_n=${topN}`, "frontend.wwi.supplier_scores", ); export const getWWIBusinessEvents = (limit = 100) => get( `/api/wwi/events?limit=${limit}`, "frontend.wwi.business_events", ); export const createWWIScenario = ( stockItemKey: number, demandMultiplier: number, ) => post( "/api/wwi/scenarios", { stock_item_key: stockItemKey, demand_multiplier: demandMultiplier }, "frontend.wwi.create_scenario", ); export const getWWIScenarios = (limit = 20) => get( `/api/wwi/scenarios?limit=${limit}`, "frontend.wwi.list_scenarios", );