import type { DataProvider } from "../../../types/data-provider"; import type { HeadlessBundleResult, HeadlessPaneDefinition, HeadlessPaneLoadArgs, } from "../../../types/plugin"; import { formatNumber, formatPercentRaw } from "../../../utils/format"; import { marketStateLabel } from "../../../market-data/market/status"; import type { MarketState } from "../../../types/financials"; import { loadWorldIndexQuotes, type WorldIndexQuoteResult } from "./client"; import { getIndicesByRegion, REGION_LABELS, REGION_ORDER, WORLD_INDICES, type IndexEntry, } from "./indices"; const COLUMNS = [ { key: "shortName", header: "Index" }, { key: "name", header: "Name" }, { key: "price", header: "Last", align: "right" as const, format: (value: unknown) => value == null ? "-" : formatNumber(Number(value), 2), }, { key: "change", header: "Change", align: "right" as const, format: (value: unknown) => value == null ? "-" : `${Number(value) >= 0 ? "+" : ""}${formatNumber(Number(value), 2)}`, }, { key: "changePercent", header: "Change %", align: "right" as const, format: (value: unknown) => value == null ? "-" : formatPercentRaw(Number(value)), }, { key: "marketState", header: "Session", format: (value: unknown) => typeof value === "string" && value ? marketStateLabel(value as MarketState) ?? value : "-", }, { key: "lastUpdated", header: "Updated", format: (value: unknown) => { const time = value == null ? Number.NaN : Number(value); return Number.isFinite(time) ? `${new Date(time).toISOString().slice(0, 16).replace("T", " ")} UTC` : "-"; }, }, ]; export function projectWorldIndicesHeadless( entries: readonly IndexEntry[], loaded: WorldIndexQuoteResult, ): HeadlessBundleResult { const grouped = getIndicesByRegion(entries); return { sections: REGION_ORDER.flatMap((region) => { const regionEntries = grouped.get(region) ?? []; if (regionEntries.length === 0) return []; return [{ title: REGION_LABELS[region], columns: COLUMNS, rows: regionEntries.map((entry) => { const quote = loaded.quotes.get(entry.symbol); return { ...entry, price: quote?.price ?? null, unit: "index points", currency: quote?.currency ?? null, change: quote?.change ?? null, changePercent: quote?.changePercent ?? null, marketState: quote?.marketState ?? null, lastUpdated: quote?.lastUpdated ?? null, }; }), }]; }), errors: loaded.errors, metadata: { requested: entries.length, available: [...loaded.quotes.values()].filter(Boolean).length, }, }; } export interface WorldIndicesHeadlessDependencies { load( args: HeadlessPaneLoadArgs, entries: readonly IndexEntry[], provider: DataProvider, ): Promise; } const defaultDependencies: WorldIndicesHeadlessDependencies = { load: (_args, entries, provider) => loadWorldIndexQuotes(entries, provider), }; export function createWorldIndicesHeadless( dependencies: WorldIndicesHeadlessDependencies = defaultDependencies, ): HeadlessPaneDefinition<"bundle"> { return { shape: "bundle", argument: { kind: "none" }, options: [], describe: "World Equity Indices", async load(args, ctx) { const loaded = await dependencies.load(args, WORLD_INDICES, ctx.marketData); return projectWorldIndicesHeadless(WORLD_INDICES, loaded); }, }; } export const worldIndicesHeadless = createWorldIndicesHeadless();