<script lang="ts">
	import { Scatter } from 'svelte-chartjs'
	import 'chartjs-adapter-date-fns'
	import zoomPlugin from 'chartjs-plugin-zoom'
	import {
		Chart as ChartJS,
		Title,
		Tooltip,
		Legend,
		LineElement,
		CategoryScale,
		LinearScale,
		PointElement,
		TimeScale,
		LogarithmicScale
	} from 'chart.js'
	import type { CompletedJob } from '$lib/gen'
	import { createEventDispatcher } from 'svelte'
	import { getDbClockNow } from '$lib/forLater'

	export let jobs: CompletedJob[] | undefined = []
	export let maxIsNow: boolean = false

	const dispatch = createEventDispatcher()

	$: success = jobs?.filter((x) => x.success)
	$: failed = jobs?.filter((x) => !x.success)
	ChartJS.register(
		Title,
		Tooltip,
		Legend,
		zoomPlugin,
		LineElement,
		CategoryScale,
		LinearScale,
		LogarithmicScale,
		PointElement,
		TimeScale
	)

	$: data = {
		labels: ['Duration'],
		datasets: [
			{
				// borderColor: 'rgba(99,0,125, .2)',
				backgroundColor: '#f87171',
				label: 'Failed',
				data:
					failed?.map((job) => ({
						x: job.started_at as any,
						y: job.duration_ms,
						id: job.id,
						path: job.script_path
					})) ?? []
			},
			{
				// borderColor: 'rgba(99,0,125, .2)',
				backgroundColor: '#4ade80',
				label: 'Successful',
				data:
					success?.map((job) => ({
						x: job.started_at as any,
						y: job.duration_ms,
						id: job.id,
						path: job.script_path
					})) ?? []
			}
		]
	}

	const zoomOptions = {
		pan: {
			enabled: true,
			modifierKey: 'ctrl' as 'ctrl',
			onPanComplete: ({ chart }) => {
				dispatch('zoom', {
					min: addSeconds(new Date(chart.scales.x.min), -1),
					max: addSeconds(new Date(chart.scales.x.max), 1)
				})
			}
		},
		zoom: {
			drag: {
				enabled: true
			},
			mode: 'x' as 'x',
			onZoom: ({ chart }) => {
				dispatch('zoom', {
					min: addSeconds(new Date(chart.scales.x.min), -1),
					max: addSeconds(new Date(chart.scales.x.max), 1)
				})
			}
		}
	}

	function getPath(x: any): string {
		return x.path
	}

	let minTime = addSeconds(new Date(), -300)
	let maxTime = getDbClockNow()

	$: computeMinMaxTime(jobs)

	function computeMinMaxTime(jobs: CompletedJob[] | undefined) {
		if (jobs == undefined || jobs?.length == 0) {
			minTime = addSeconds(new Date(), -300)
			maxTime = getDbClockNow()
			return
		}

		const maxJob = maxIsNow ? getDbClockNow() : new Date(jobs?.[0].started_at)
		const minJob = new Date(jobs?.[jobs?.length - 1].started_at)

		const diff = (maxJob.getTime() - minJob.getTime()) / 20000

		minTime = addSeconds(minJob, -diff)
		if (maxIsNow) {
			maxTime = maxJob
		} else {
			maxTime = addSeconds(maxJob, diff)
		}
	}

	function addSeconds(date: Date, seconds: number): Date {
		date.setTime(date.getTime() + seconds * 1000)
		return date
	}

	$: scatterOptions = {
		responsive: true,
		maintainAspectRatio: false,
		plugins: {
			zoom: zoomOptions,
			legend: {
				display: false
			},
			tooltip: {
				callbacks: {
					label: function (context) {
						return getPath(context.raw)
					}
				}
			}
		},

		scales: {
			x: {
				type: 'time',
				grid: {
					display: false
				},
				min: minTime,
				max: maxTime
			},
			y: {
				grid: {
					display: false
				},
				title: {
					display: true,
					text: 'job duration (ms)'
				},
				type: 'logarithmic'
			}
		},
		animation: false
	} as any
</script>

<div class="relative max-h-40">
	<Scatter {data} options={scatterOptions} />
</div>
