package layout

import "git.haelnorr.com/h/oslstats/internal/view/component/popup"
import "git.haelnorr.com/h/oslstats/internal/view/component/nav"
import "git.haelnorr.com/h/oslstats/internal/view/component/footer"
import "git.haelnorr.com/h/oslstats/pkg/contexts"

// Global page layout. Includes HTML document settings, header tags
// navbar and footer
templ Global(title string) {
	{{ htmxLogging := contexts.HTMXLog(ctx) }}
	<!DOCTYPE html>
	<html
		lang="en"
		x-data="{
            theme: localStorage.getItem('theme')
            || 'system'}"
		x-init="$watch('theme', (val) => localStorage.setItem('theme', val))"
		x-bind:class="{'dark': theme === 'dark' || (theme === 'system' &&
            window.matchMedia('(prefers-color-scheme: dark)').matches)}"
	>
		<head>
			<script src="/static/js/theme.js"></script>
			<meta charset="UTF-8"/>
			<meta name="viewport" content="width=device-width, initial-scale=1"/>
			<title>{ title }</title>
			<link rel="icon" type="image/x-icon" href="/static/favicon.ico"/>
			<link href="/static/css/output.css" rel="stylesheet"/>
			<script src="https://unpkg.com/htmx.org@2.0.4" integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+" crossorigin="anonymous"></script>
			<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.x.x/dist/cdn.min.js"></script>
			<script src="https://unpkg.com/alpinejs" defer></script>
			if htmxLogging {
				<script>
					htmx.logAll();
				</script>
			}
		<script>
			const bodyData = {
				// Error modal (blocking, full-screen) - for 500/503 errors
				errorModal: {
					show: false,
					code: 0,
					title: '',
					message: '',
					details: ''
				},
				
				// Toast notifications (non-blocking, stacked) - for success/warning/info
				toasts: [],
				toastIdCounter: 0,
				
			// Handle HTMX beforeSwap event - intercept both errors and successes
			handleBeforeSwap(event) {
				const xhr = event.detail.xhr;
				if (!xhr) return;
				
				const status = xhr.status;
				const trigger = xhr.getResponseHeader('HX-Trigger');
				if (!trigger) return;
				
				try {
					const data = JSON.parse(trigger);
					
					// Handle 500/503 error modals
					if ((status === 500 || status === 503) && data.showErrorModal) {
						this.errorModal = {
							show: true,
							code: data.showErrorModal.code,
							title: data.showErrorModal.title,
							message: data.showErrorModal.message,
							details: data.showErrorModal.details
						};
						// Prevent swap but allow error logging
						event.detail.shouldSwap = false;
						return;
					}
					
					// Handle success/warning/info toasts (200-299)
					if (status >= 200 && status < 300 && data.showNotification) {
						this.addToast(data.showNotification);
					}
				} catch (e) {
					console.error('Failed to parse HX-Trigger:', e);
				}
			},
				
				// Add toast to stack
				addToast(notification) {
					const toast = {
						id: ++this.toastIdCounter,
						type: notification.type,
						title: notification.title,
						message: notification.message,
						paused: false,
						progress: 0
					};
					
					this.toasts.push(toast);
					
					// Determine timeout based on type
					const timeout = notification.type === 'warning' ? 5000 : 3000;
					
					// Start progress animation
					this.animateToastProgress(toast.id, timeout);
				},
				
			// Animate toast progress bar and auto-dismiss
			animateToastProgress(toastId, duration) {
				const toast = this.toasts.find(t => t.id === toastId);
				if (!toast) return;
				
				const startTime = performance.now();
				let totalPausedTime = 0;
				let pauseStartTime = null;
				
				const animate = (currentTime) => {
					const toast = this.toasts.find(t => t.id === toastId);
					if (!toast) return; // Toast was manually removed
					
					if (toast.paused) {
						// Track when pause started
						if (pauseStartTime === null) {
							pauseStartTime = currentTime;
						}
						// Keep animating while paused
						requestAnimationFrame(animate);
						return;
					} else {
						// If we were paused, accumulate the paused time
						if (pauseStartTime !== null) {
							totalPausedTime += currentTime - pauseStartTime;
							pauseStartTime = null;
						}
					}
					
					// Calculate actual elapsed time (excluding paused time)
					const elapsed = currentTime - startTime - totalPausedTime;
					toast.progress = Math.min((elapsed / duration) * 100, 100);
					
					if (elapsed >= duration) {
						this.removeToast(toastId);
					} else {
						requestAnimationFrame(animate);
					}
				};
				
				requestAnimationFrame(animate);
			},
				
				// Remove toast from stack
				removeToast(id) {
					this.toasts = this.toasts.filter(t => t.id !== id);
				},
				
				// Close error modal
				closeErrorModal() {
					this.errorModal.show = false;
				}
			};
		</script>
		</head>
	<body
		class="bg-base text-text ubuntu-mono-regular overflow-x-hidden"
		x-data="bodyData"
		x-on:htmx:before-swap="handleBeforeSwap($event)"
		x-on:keydown.escape.window="closeErrorModal()"
	>
		@popup.ErrorModal()
		@popup.ToastContainer()
			<div
				id="main-content"
				class="flex flex-col h-screen justify-between"
			>
				@nav.Navbar()
				<div id="page-content" class="mb-auto md:px-5 md:pt-5">
					{ children... }
				</div>
				@footer.Footer()
			</div>
		</body>
	</html>
}
