<!--
  Compact CPU/memory stats bars with an optional expandable history
  chart. Workload-scoped only after the hard cutover — pass the
  workload + container-row identifiers; the legacy project-instance and
  static-site variants targeted dead endpoints.
-->
<script lang="ts">
	import type { ContainerStats, ContainerStatsSample } from '$lib/types';
	import * as api from '$lib/api';
	import { t } from '$lib/i18n';
	import { statsInterval } from '$lib/stores/statsInterval';
	import ResourceChart from './ResourceChart.svelte';
	import Sparkline from './Sparkline.svelte';
	import type { EChartsOption } from 'echarts';

	export type StatsSource = {
		kind: 'workload';
		workloadId: string;
		containerRowId: string;
	};

	interface Props {
		source: StatsSource;
		historyWindow?: '30m' | '2h' | '6h' | '24h';
	}

	const { source, historyWindow = '2h' }: Props = $props();

	let stats = $state<ContainerStats | null>(null);
	let history = $state<ContainerStatsSample[]>([]);
	// Short rolling window for the always-visible sparklines. Kept separate
	// from `history` (which is sized to `historyWindow` and only loaded on
	// expand) so the inline trend doesn't change zoom every time the user
	// switches the chart range.
	let sparkSamples = $state<ContainerStatsSample[]>([]);
	let error = $state(false);
	let expanded = $state(false);

	async function fetchStats(signal: AbortSignal): Promise<ContainerStats> {
		return api.fetchWorkloadContainerStats(source.workloadId, source.containerRowId, signal);
	}

	async function fetchHistory(signal: AbortSignal, win: string = historyWindow): Promise<ContainerStatsSample[]> {
		return api.fetchWorkloadContainerStatsHistory(
			source.workloadId,
			source.containerRowId,
			win,
			signal
		);
	}

	$effect(() => {
		let controller = new AbortController();

		async function load() {
			controller.abort();
			controller = new AbortController();
			try {
				const [result, spark] = await Promise.all([
					fetchStats(controller.signal),
					// Always pull a 30-minute rolling window for the inline
					// sparkline. Cheap query and gives the user a trend hint
					// without forcing them to expand the full history chart.
					fetchHistory(controller.signal, '30m').catch(() => [] as ContainerStatsSample[])
				]);
				stats = result;
				sparkSamples = spark;
				error = false;
				if (expanded) {
					history = await fetchHistory(controller.signal);
				}
			} catch (e) {
				if (e instanceof DOMException && e.name === 'AbortError') return;
				error = true;
			}
		}

		load();
		const interval = setInterval(load, 30_000);

		return () => {
			controller.abort();
			clearInterval(interval);
		};
	});

	import { formatBytes } from '$lib/format/bytes';

	const cpuColor = $derived.by(() => {
		if (!stats) return 'bg-gray-300';
		if (stats.cpu_percent > 80) return 'bg-red-500';
		if (stats.cpu_percent > 50) return 'bg-amber-500';
		return 'bg-emerald-500';
	});

	const memColor = $derived.by(() => {
		if (!stats) return 'bg-gray-300';
		if (stats.memory_percent > 80) return 'bg-red-500';
		if (stats.memory_percent > 50) return 'bg-amber-500';
		return 'bg-blue-500';
	});

	// CPU samples normalize to absolute percent (already 0-100 from the
	// collector). Memory samples need percent-of-limit so the sparkline
	// matches the bar's denominator.
	const cpuSpark = $derived(sparkSamples.map((s) => s.cpu_percent));
	const memSpark = $derived(
		sparkSamples.map((s) => (s.memory_limit > 0 ? (s.memory_usage / s.memory_limit) * 100 : 0))
	);

	const historyOption = $derived<EChartsOption>({
		animation: false,
		grid: { top: 8, right: 10, bottom: 24, left: 40 },
		tooltip: {
			trigger: 'axis',
			valueFormatter: (v) => (typeof v === 'number' ? v.toFixed(1) + '%' : String(v))
		},
		legend: {
			data: [$t('resources.cpuSeries'), $t('resources.memorySeries')],
			bottom: 0,
			textStyle: { fontSize: 10 }
		},
		xAxis: { type: 'time', axisLabel: { fontSize: 10, color: '#94a3b8' } },
		yAxis: {
			type: 'value',
			min: 0,
			max: 100,
			axisLabel: { fontSize: 10, color: '#94a3b8', formatter: '{value}%' },
			splitLine: { lineStyle: { color: 'rgba(148,163,184,0.15)' } }
		},
		series: [
			{
				name: $t('resources.cpuSeries'),
				type: 'line',
				smooth: true,
				showSymbol: false,
				data: history.map((s) => [s.ts * 1000, Number(s.cpu_percent.toFixed(2))]),
				lineStyle: { color: '#10b981', width: 2 },
				areaStyle: { color: 'rgba(16, 185, 129, 0.15)' }
			},
			{
				name: $t('resources.memorySeries'),
				type: 'line',
				smooth: true,
				showSymbol: false,
				data: history.map((s) => {
					const pct = s.memory_limit > 0 ? (s.memory_usage / s.memory_limit) * 100 : 0;
					return [s.ts * 1000, Number(pct.toFixed(2))];
				}),
				lineStyle: { color: '#3b82f6', width: 2 },
				areaStyle: { color: 'rgba(59, 130, 246, 0.15)' }
			}
		]
	});
</script>

{#if stats}
	<div class="mt-2 space-y-1">
		<!-- CPU bar + 30m sparkline -->
		<div class="flex items-center gap-2">
			<span class="w-8 text-[10px] font-medium text-[var(--text-tertiary)]">{$t('stats.cpu')}</span>
			<div class="relative h-1.5 flex-1 overflow-hidden rounded-full bg-[var(--surface-card-hover)]">
				<div
					class="absolute inset-y-0 left-0 rounded-full transition-all duration-500 {cpuColor}"
					style="width: {Math.min(stats.cpu_percent, 100)}%"
				></div>
			</div>
			<span class="text-emerald-500 dark:text-emerald-400" aria-hidden="true">
				<Sparkline values={cpuSpark} width={64} height={14} color="currentColor" fill="rgba(16,185,129,0.18)" ariaLabel={$t('resources.cpuSeries')} />
			</span>
			<span class="w-10 text-right text-[10px] tabular-nums text-[var(--text-tertiary)]">
				{stats.cpu_percent.toFixed(1)}%
			</span>
		</div>
		<!-- Memory bar + 30m sparkline -->
		<div class="flex items-center gap-2">
			<span class="w-8 text-[10px] font-medium text-[var(--text-tertiary)]">{$t('stats.mem')}</span>
			<div class="relative h-1.5 flex-1 overflow-hidden rounded-full bg-[var(--surface-card-hover)]">
				<div
					class="absolute inset-y-0 left-0 rounded-full transition-all duration-500 {memColor}"
					style="width: {Math.min(stats.memory_percent, 100)}%"
				></div>
			</div>
			<span class="text-blue-500 dark:text-blue-400" aria-hidden="true">
				<Sparkline values={memSpark} width={64} height={14} color="currentColor" fill="rgba(59,130,246,0.18)" ariaLabel={$t('resources.memorySeries')} />
			</span>
			<span class="w-24 text-right text-[10px] tabular-nums text-[var(--text-tertiary)]">
				{formatBytes(stats.memory_usage)} / {formatBytes(stats.memory_limit)}
			</span>
		</div>

		<button
			type="button"
			class="mt-1 text-[10px] text-[var(--text-tertiary)] hover:text-[var(--text-secondary)]"
			onclick={() => (expanded = !expanded)}
		>
			{expanded ? '▾ ' + $t('resources.hideHistory') : '▸ ' + $t('resources.showHistory')}
		</button>

		{#if expanded}
			{#if history.length === 0}
				<p class="mt-1 text-[10px] text-[var(--text-tertiary)]">
					{$statsInterval > 0
						? $t('resources.noSamples', { interval: String($statsInterval) })
						: $t('resources.collectionDisabled')}
				</p>
			{:else}
				<div class="mt-1 rounded-md border border-[var(--border-primary)] bg-[var(--surface-page)] p-2">
					<ResourceChart option={historyOption} height="140px" ariaLabel={$t('resources.workloadUtilization')} />
				</div>
			{/if}
		{/if}
	</div>
{:else if error}
	<p class="mt-2 text-[10px] text-[var(--text-tertiary)]">{$t('stats.unavailable')}</p>
{/if}
