<script lang="ts">
	/**
	 * WorkloadMetricsPanel
	 *
	 * Per-workload CPU + memory time-series for /apps/[id]. Reuses the global
	 * ResourceChart (ECharts) but scoped to one workload's containers, summed
	 * per timestamp server-side. CPU is plotted as a percentage on the left
	 * axis; memory as absolute MiB on the right axis (the container memory
	 * limit is often 0/unlimited, so a percentage would be meaningless).
	 *
	 * Stats live in SQLite, so the chart works even when the Docker daemon is
	 * down; an empty series simply means collection is off or the app is new.
	 */
	import * as api from '$lib/api';
	import type { EChartsOption } from 'echarts';
	import { t } from '$lib/i18n';
	import { formatBytes } from '$lib/format/bytes';
	import ResourceChart from './ResourceChart.svelte';

	interface Props {
		workloadId: string;
	}
	let { workloadId }: Props = $props();

	type Window = '30m' | '2h' | '6h';
	const WINDOWS: Window[] = ['30m', '2h', '6h'];

	let points = $state<api.WorkloadStatsPoint[]>([]);
	let window = $state<Window>('2h');
	let loading = $state(true);
	let error = $state('');

	async function load(signal?: AbortSignal): Promise<void> {
		try {
			points = await api.fetchWorkloadStatsHistory(workloadId, window, signal);
			error = '';
		} catch (e) {
			if (e instanceof DOMException && e.name === 'AbortError') return;
			error = e instanceof Error ? e.message : String(e);
		} finally {
			loading = false;
		}
	}

	// Reload on workloadId/window change and poll while mounted (matches the
	// dashboard resources card cadence).
	$effect(() => {
		void workloadId;
		void window;
		loading = true;
		const controller = new AbortController();
		load(controller.signal);
		const id = setInterval(() => load(controller.signal), 15_000);
		return () => {
			controller.abort();
			clearInterval(id);
		};
	});

	const MIB = 1024 * 1024;

	const chartOption = $derived<EChartsOption>({
		animation: false,
		grid: { top: 8, right: 48, bottom: 24, left: 44 },
		tooltip: {
			trigger: 'axis',
			axisPointer: { type: 'line' }
		},
		legend: {
			data: [$t('apps.detail.metrics.cpuSeries'), $t('apps.detail.metrics.memorySeries')],
			bottom: 0,
			textStyle: { fontSize: 11 }
		},
		xAxis: {
			type: 'time',
			axisLabel: { fontSize: 10, color: '#94a3b8' }
		},
		yAxis: [
			{
				type: 'value',
				min: 0,
				axisLabel: { fontSize: 10, color: '#94a3b8', formatter: '{value}%' },
				splitLine: { lineStyle: { color: 'rgba(148,163,184,0.15)' } }
			},
			{
				type: 'value',
				min: 0,
				axisLabel: { fontSize: 10, color: '#94a3b8', formatter: '{value} MiB' },
				splitLine: { show: false }
			}
		],
		series: [
			{
				name: $t('apps.detail.metrics.cpuSeries'),
				type: 'line',
				yAxisIndex: 0,
				smooth: true,
				showSymbol: false,
				data: points.map((p) => [p.ts * 1000, Number(p.cpu_percent.toFixed(2))]),
				lineStyle: { color: '#10b981', width: 2 },
				areaStyle: { color: 'rgba(16, 185, 129, 0.15)' }
			},
			{
				name: $t('apps.detail.metrics.memorySeries'),
				type: 'line',
				yAxisIndex: 1,
				smooth: true,
				showSymbol: false,
				data: points.map((p) => [p.ts * 1000, Number((p.memory_usage / MIB).toFixed(1))]),
				lineStyle: { color: '#3b82f6', width: 2 },
				areaStyle: { color: 'rgba(59, 130, 246, 0.15)' }
			}
		]
	});

	// Latest reading for the at-a-glance summary line above the chart.
	const latest = $derived(points.length > 0 ? points[points.length - 1] : null);
</script>

<section class="panel wm-panel" aria-labelledby="wm-heading">
	<span class="reg reg-tl" aria-hidden="true"></span>
	<span class="reg reg-tr" aria-hidden="true"></span>
	<span class="reg reg-bl" aria-hidden="true"></span>
	<span class="reg reg-br" aria-hidden="true"></span>

	<header class="panel-head">
		<h2 class="panel-title" id="wm-heading">
			{$t('apps.detail.metrics.title')}<span class="title-accent">.</span>
		</h2>
		<span class="panel-sub">{$t('apps.detail.metrics.sub')}</span>
		<div class="wm-windows" role="group" aria-label={$t('apps.detail.metrics.windowLabel')}>
			{#each WINDOWS as w (w)}
				<button class="wm-win" class:active={window === w} onclick={() => (window = w)}>{w}</button>
			{/each}
		</div>
	</header>

	{#if error}
		<div class="alert inline-alert" role="alert">
			<span class="alert-tag">ERR</span><span>{error}</span>
		</div>
	{/if}

	{#if loading && points.length === 0}
		<p class="hint">{$t('apps.detail.metrics.loading')}</p>
	{:else if points.length === 0}
		<p class="hint">{$t('apps.detail.metrics.empty')}</p>
	{:else}
		{#if latest}
			<p class="wm-summary">
				<span class="wm-stat"
					><span class="wm-dot cpu"></span>{$t('apps.detail.metrics.cpuSeries')}:
					<strong>{latest.cpu_percent.toFixed(1)}%</strong></span
				>
				<span class="wm-stat"
					><span class="wm-dot mem"></span>{$t('apps.detail.metrics.memorySeries')}:
					<strong>{formatBytes(latest.memory_usage)}</strong></span
				>
			</p>
		{/if}
		<ResourceChart option={chartOption} height="180px" ariaLabel={$t('apps.detail.metrics.title')} />
	{/if}
</section>

<style>
	.wm-panel {
		margin-top: 1rem;
	}
	.panel-head {
		display: flex;
		align-items: baseline;
		gap: 0.5rem;
		flex-wrap: wrap;
	}
	.wm-windows {
		margin-left: auto;
		display: flex;
		gap: 0.25rem;
	}
	.wm-win {
		font-size: 0.7rem;
		padding: 0.15rem 0.5rem;
		border: 1px solid var(--border-primary);
		border-radius: 4px;
		background: transparent;
		color: var(--text-secondary);
		cursor: pointer;
	}
	.wm-win.active {
		background: var(--accent-soft, rgba(16, 185, 129, 0.15));
		color: var(--text-primary);
		border-color: var(--accent, #10b981);
	}
	.hint {
		font-size: 0.72rem;
		color: var(--text-tertiary);
		margin: 0.3rem 0;
	}
	.wm-summary {
		display: flex;
		gap: 1rem;
		font-size: 0.74rem;
		color: var(--text-secondary);
		margin: 0.3rem 0 0.5rem;
	}
	.wm-stat {
		display: inline-flex;
		align-items: center;
		gap: 0.3rem;
	}
	.wm-dot {
		width: 8px;
		height: 8px;
		border-radius: 50%;
		display: inline-block;
	}
	.wm-dot.cpu {
		background: #10b981;
	}
	.wm-dot.mem {
		background: #3b82f6;
	}
</style>
