<script setup lang="ts">
import Loading from '@/components/Loading.vue';
import { ref, onMounted, onUnmounted } from 'vue';
import { api } from '../services/api';
import MetricRow from './MetricRow.vue';

const d = ref<any>(null);
const history = ref<number[]>([]);
const canvas = ref<HTMLCanvasElement | null>(null);
const W = 640, H = 120, MAX_PTS = 120;
const SEG_W = W / (MAX_PTS - 1);
const SUB = 4;

let interval: ReturnType<typeof setInterval>;
let rafId: number;
let drawProgress = 0;
let lastTimestamp = 0;
const ANIM_DURATION = 1200;

let pointBuffer: { x: number; y: number }[] = [];
let prevMax = 1.0;

function buildBuffer(pts: number[]) {
	if (pts.length < 2) return;
	const mid = H / 2, amp = H / 2 - 6;
	const newMax = Math.max(...pts, 1.0);
	prevMax = prevMax + (newMax - prevMax) * 0.15;
	const buf: { x: number; y: number }[] = [];

	pts.forEach((v, i) => {
		const prev = pts[i - 1] ?? v;
		const max = prevMax;
		const prevNorm = prev === 0 ? 0 : (prev / max) * amp;
		const norm = v === 0 ? 0 : (v / max) * amp;
		const baseX = i * SEG_W;
		const s = SEG_W / SUB;

		const a0 = prevNorm * 0.75 + norm * 0.25;
		const a1 = prevNorm * 0.25 + norm * 0.75;
		const a2 = norm;

		buf.push({ x: baseX,         y: mid - a0 }); // up
		buf.push({ x: baseX + s,     y: mid - a1 }); // up peak
		buf.push({ x: baseX + s * 2, y: mid + a2 }); // down
		buf.push({ x: baseX + s * 3, y: mid });       // back to exact center ✓
	});

	pointBuffer = buf;
}

function draw(timestamp: number) {
	const ctx = canvas.value?.getContext('2d');
	if (!ctx) { rafId = requestAnimationFrame(draw); return; }

	const dt = Math.min(timestamp - lastTimestamp, 100);
	lastTimestamp = timestamp;
	drawProgress = Math.min(1, drawProgress + dt / ANIM_DURATION);

	ctx.clearRect(0, 0, W, H);

	// Center line — full width
	ctx.beginPath();
	ctx.strokeStyle = 'rgba(255,255,255,0.1)';
	ctx.lineWidth = 1;
	ctx.moveTo(0, H / 2);
	ctx.lineTo(W, H / 2);
	ctx.stroke();

	if (pointBuffer.length < 2) { rafId = requestAnimationFrame(draw); return; }

	// Shift the whole path left by PAD_SEGS segments so tip never hits the edge
	const xOffset = 3 * SEG_W;

	const settledCount = pointBuffer.length - SUB;
	const anchor = pointBuffer[settledCount - 1];
	const totalSteps = SUB + 1;
	const animFrac = drawProgress * totalSteps;
	const animFloor = Math.floor(animFrac);
	const animRemainder = animFrac - animFloor;

	ctx.beginPath();
	ctx.strokeStyle = '#4d9fff';
	ctx.lineWidth = 1.5;
	ctx.lineJoin = 'round';

	for (let i = 0; i < settledCount; i++) {
		const p = pointBuffer[i];
		const x = p.x - xOffset;
		i === 0 ? ctx.moveTo(x, p.y) : ctx.lineTo(x, p.y);
	}

	const animPoints = [
		anchor,
		...Array.from({ length: SUB }, (_, i) => pointBuffer[settledCount + i]),
	];

	for (let i = 1; i <= animFloor && i < animPoints.length; i++) {
		ctx.lineTo(animPoints[i].x - xOffset, animPoints[i].y);
	}

	if (animFloor < animPoints.length - 1 && animRemainder > 0) {
		const curr = animPoints[animFloor];
		const next = animPoints[animFloor + 1];
		ctx.lineTo(
			curr.x + (next.x - curr.x) * animRemainder - xOffset,
			curr.y + (next.y - curr.y) * animRemainder,
		);
	}

	ctx.stroke();
	rafId = requestAnimationFrame(draw);
}

async function poll() {
	d.value = await api.current('seismic_magnitude');
	history.value.push(d.value.seismic_magnitude ?? 0);
	if (history.value.length > MAX_PTS) history.value.shift();
	buildBuffer(history.value);
	drawProgress = 0;
}

onMounted(async () => {
	await poll();
	lastTimestamp = performance.now();
	rafId = requestAnimationFrame(draw);
	interval = setInterval(poll, 1000);
});

onUnmounted(() => {
	clearInterval(interval);
	cancelAnimationFrame(rafId);
});
</script>

<style scoped lang="scss">
canvas { width: 100%; height: 60px; }
</style>

<template>
	<div class="card">
		<div class="card-title">🫨 Seismic</div>
		<div v-if="!d" class="p-2">
			<div class="w-100 pos-rel br-2 overflow-hidden" style="height: 80px">
				<Loading />
			</div>
		</div>
		<template v-else>
			<MetricRow label="Magnitude" :value="d.seismic_magnitude?.toFixed(1)" metric-key="seismic_magnitude" :data="d" />
			<canvas ref="canvas" :width="W" :height="H" />
		</template>
	</div>
</template>
