<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 canvas = ref<HTMLCanvasElement | null>(null);

const AXES = [
	{ key: 'seismic_x', label: 'X', color: '#ccc' },
	{ key: 'seismic_y', label: 'Y', color: '#ccc' },
	{ key: 'seismic_z', label: 'Z', color: '#ccc' },
];

const W = 640, BAND = 80, H = BAND * AXES.length, MAX_PTS = 120;
const SEG_W = W / (MAX_PTS - 1);
const SUB = 4;
const RIGHT_PAD = 2 * SEG_W;

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

type Pt = { x: number; y: number };
const traces = AXES.map(() => ({
	history: [] as number[],
	prevMax: 1.0,
	buffer: [] as Pt[],
}));

function buildBuffer(t: (typeof traces)[number], band: number) {
	const pts = t.history;
	if (pts.length < 2) return;
	const mid = band * BAND + BAND / 2, amp = BAND / 2 - 6;
	const newMax = Math.max(...pts, 1.0);
	t.prevMax = t.prevMax + (newMax - t.prevMax) * 0.15; // eased amplitude scale
	const tipX = W - RIGHT_PAD;
	const buf: Pt[] = [];

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

		// one oscillation per value, amplitude fading prevNorm → norm
		const a0 = prevNorm * 0.75 + norm * 0.25;
		const a1 = prevNorm * 0.25 + norm * 0.75;

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

	t.buffer = buf;
}

function drawTrace(ctx: CanvasRenderingContext2D, t: (typeof traces)[number], color: string) {
	const buf = t.buffer;
	if (buf.length <= SUB) return;

	// slide everything left as the new segment draws in
	const slide = (1 - drawProgress) * SEG_W;

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

	ctx.beginPath();
	ctx.strokeStyle = color;
	ctx.lineWidth = 1;
	ctx.lineJoin = 'round';

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

	const animPoints = [anchor, ...buf.slice(settledCount)];

	for (let i = 1; i <= animFloor && i < animPoints.length; i++) {
		ctx.lineTo(animPoints[i].x + slide, 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 + slide,
			curr.y + (next.y - curr.y) * animRemainder,
		);
	}

	ctx.stroke();
}

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);

	AXES.forEach((_, i) => {
		const mid = i * BAND + BAND / 2;

		// Axis label — top-left of each band
		ctx.font = '16px monospace';
		ctx.fillStyle = AXES[i].color;
		ctx.globalAlpha = 0.6;
		ctx.fillText(AXES[i].label, W - 20, i * BAND + 14);
		ctx.globalAlpha = 1;

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

		drawTrace(ctx, traces[i], AXES[i].color);
	});

	rafId = requestAnimationFrame(draw);
}

async function poll() {
	d.value = await api.current('seismic_magnitude,seismic_x,seismic_y,seismic_z');
	AXES.forEach((axis, i) => {
		const t = traces[i];
		t.history.push(d.value[axis.key] ?? 0);
		if (t.history.length > MAX_PTS) t.history.shift();
		buildBuffer(t, i);
	});
	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: 180px; }
</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 mb-2" style="height: 30px">
				<Loading />
			</div>
			<div class="w-100 pos-rel br-2 overflow-hidden" style="height: 150px">
				<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>
