<script setup lang="ts">
import {computed, ref, onMounted} from 'vue';
import {Line} from 'vue-chartjs';
import {
	Chart as ChartJS, CategoryScale, LinearScale, PointElement,
	LineElement, Tooltip, Legend, Filler, type ChartOptions
} from 'chart.js';
import {METRICS, formatValue} from '../services/units';
import type {DataRow} from '../services/api';
import {api} from '../services/api';

ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Tooltip, Legend, Filler);

const props = defineProps<{metricKey: string; currentData: DataRow}>();

const historic = ref<DataRow[]>([]);
const forecast = ref<DataRow[]>([]);
const loading = ref(true);
const meta = computed(() => METRICS[props.metricKey]);

onMounted(async () => {
	const start = new Date(Date.now() - 24 * 3600000);
	const end = new Date(Date.now() + 48 * 3600000);
	const hourly = await api.hourly(start, end);
	historic.value = hourly.filter((h: any) => new Date(h.time).getTime() <= Date.now());
	forecast.value = hourly.filter((h: any) => new Date(h.time).getTime() > Date.now());
	loading.value = false;
});

const nowLabel = computed(() => {
	const d = new Date();
	return `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}`;
});

const chartData = computed(() => {
	const color = meta.value?.color ?? '#38bdf8';
	const histLabels = historic.value.map(r => r.time as string);
	const foreLabels = forecast.value.map(r => r.time as string);
	const histVals = historic.value.map(r => r[props.metricKey] as number);
	const foreVals = forecast.value.map(r => r[props.metricKey] as number);
	const currentVal = props.currentData[props.metricKey] as number | null;

	const allLabels = [...histLabels, nowLabel.value, ...foreLabels];
	const histData = [...histVals, currentVal, ...foreVals.map(() => null)];
	const foreData = [...histVals.map(() => null), currentVal, ...foreVals];

	return {
		labels: allLabels,
		datasets: [
			{
				label: 'Historic',
				data: histData,
				borderColor: color,
				backgroundColor: `${color}22`,
				borderWidth: 2,
				pointRadius: 0,
				tension: 0.3,
				fill: true,
				spanGaps: false,
			},
			{
				label: 'Forecast',
				data: foreData,
				borderColor: color,
				backgroundColor: 'transparent',
				borderWidth: 2,
				borderDash: [6, 4],
				pointRadius: 0,
				tension: 0.3,
				fill: false,
				spanGaps: false,
			},
			{
				label: 'Now',
				data: allLabels.map(l => l === nowLabel.value ? currentVal : null),
				borderColor: '#ffffff88',
				backgroundColor: color,
				pointRadius: 6,
				pointHoverRadius: 8,
				borderWidth: 0,
				showLine: false,
				spanGaps: false,
			}
		]
	};
});

const chartOptions = computed<ChartOptions<'line'>>(() => ({
	responsive: true,
	maintainAspectRatio: false,
	interaction: {mode: 'index', intersect: false},
	plugins: {
		legend: {display: false},
		tooltip: {
			callbacks: {
				label: ctx => formatValue(props.metricKey, ctx.parsed.y),
			}
		}
	},
	scales: {
		x: {
			ticks: {
				color: 'var(--text-muted)',
				maxTicksLimit: 12,
				maxRotation: 0,
				callback(val, i) {
					const lbl = this.getLabelForValue(i);
					return lbl?.length === 5 && lbl.endsWith(':00') ? lbl : '';
				}
			},
			grid: {color: 'var(--border)'},
		},
		y: {
			ticks: {color: 'var(--text-muted)', callback: v => formatValue(props.metricKey, v as number)},
			grid: {color: 'var(--border)'},
		}
	},
	annotation: {
		annotations: {
			nowLine: {
				type: 'line',
				xMin: nowLabel.value,
				xMax: nowLabel.value,
				borderColor: '#ffffff44',
				borderWidth: 1,
				borderDash: [4, 4],
			}
		}
	}
}));
</script>

<style scoped lang="scss">
.chart-wrap {
	position: relative;
	height: 260px;
	width: 100%;
}

.loading {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 260px;
	color: var(--text-muted);
	font-size: 14px;
}
</style>

<template>
	<div v-if="loading" class="loading">Loading chart…</div>
	<div v-else class="chart-wrap">
		<Line :data="chartData" :options="chartOptions"/>
	</div>
</template>
