import { useMemo } from 'react' import { Activity, AlertTriangle, Gauge, HeartPulse, Timer, TrendingUp, } from 'lucide-react' import { useTranslation } from 'react-i18next' import { cn } from '@/lib/utils' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { GroupBadge } from '@/components/group-badge' import { aggregateUptime, buildGroupPerformance, buildLatencyTimeSeries, buildUptimeSeries, formatLatency, formatThroughput, formatUptimePct, type UptimeDayPoint, } from '../lib/mock-stats' import type { PricingModel } from '../types' import { LatencyTrendChart, ThroughputBarChart, UptimeBarChart, } from './model-details-charts' import { UptimeSparkline } from './model-details-uptime-sparkline' const COMPACT_NUMBER = new Intl.NumberFormat(undefined, { notation: 'compact', maximumFractionDigits: 1, }) function StatCard(props: { icon: React.ComponentType<{ className?: string }> label: string value: React.ReactNode hint?: string intent?: 'default' | 'warning' | 'success' }) { const Icon = props.icon const intent = props.intent ?? 'default' return (
{props.label} {props.value} {props.hint && ( {props.hint} )}
) } export function ModelDetailsPerformance(props: { model: PricingModel }) { const { t } = useTranslation() const performances = useMemo( () => buildGroupPerformance(props.model), [props.model] ) const latencySeries = useMemo( () => buildLatencyTimeSeries(props.model), [props.model] ) const uptimeSeries = useMemo( () => buildUptimeSeries(props.model), [props.model] ) const aggregated = useMemo( () => aggregateUptime(uptimeSeries), [uptimeSeries] ) const uptimeByGroup = useMemo>(() => { const map: Record = {} for (const perf of performances) { map[perf.group] = buildUptimeSeries(props.model, perf.group) } return map }, [performances, props.model]) if (performances.length === 0) { return (
{t('Performance data is not yet available for this model.')}
) } const bestTtft = Math.min(...performances.map((p) => p.ttft_p50_ms)) const bestThroughput = Math.max(...performances.map((p) => p.throughput_tps)) const totalRequests = performances.reduce( (s, p) => s + p.request_volume_24h, 0 ) const intent = aggregated.uptime_pct >= 99.9 ? 'success' : aggregated.uptime_pct >= 99 ? 'default' : 'warning' const headerCellClass = 'text-muted-foreground py-2 text-[10px] font-medium tracking-wider uppercase' return (
0 ? t('{{count}} incidents in the last 30 days', { count: aggregated.incidents, }) : t('No incidents in the last 30 days') } intent={intent} />
{t('Group')} {t('TTFT P50')} {t('TTFT P95')} {t('TTFT P99')} {t('Throughput')} {t('Uptime (30d)')} {t('Requests / 24h')} {performances.map((perf) => { const isBestTtft = perf.ttft_p50_ms === bestTtft const isBestTput = perf.throughput_tps === bestThroughput return ( {formatLatency(perf.ttft_p50_ms)} {formatLatency(perf.ttft_p95_ms)} {formatLatency(perf.ttft_p99_ms)} 0 && 'text-emerald-600 dark:text-emerald-400' )} > {formatThroughput(perf.throughput_tps)} {COMPACT_NUMBER.format(perf.request_volume_24h)} ) })}
{bestThroughput > 0 && (
)}
0 ? t( 'Daily uptime; {{incidents}} incidents totalling {{minutes}} minutes', { incidents: aggregated.incidents, minutes: aggregated.outage_minutes, } ) : t('Daily uptime over the last 30 days') } accent={ aggregated.incidents > 0 ? ( {t('{{count}} incidents', { count: aggregated.incidents, })} ) : null } />

{t( 'Performance metrics shown here are simulated for preview purposes and will be replaced with live observability data once the backend integration is complete.' )}

) } function SectionHeader(props: { icon: React.ComponentType<{ className?: string }> title: string description?: string accent?: React.ReactNode }) { const Icon = props.icon return (
{props.title}
{props.description && (

{props.description}

)}
{props.accent && (
{props.accent}
)}
) }