<script lang="ts">
	import { cn } from '$lib/utils/cn.js';

	interface Props {
		checked?: boolean | undefined;
		onchange?: (checked: boolean) => void;
		disabled?: boolean;
		id?: string;
		name?: string;
		label?: string;
		ariaLabel?: string;
		ariaLabelledby?: string;
		size?: 'sm' | 'md';
		class?: string;
	}

	let {
		checked = $bindable(false),
		onchange,
		disabled = false,
		id,
		name,
		label,
		ariaLabel,
		ariaLabelledby,
		size = 'md',
		class: className = ''
	}: Props = $props();

	function toggle() {
		if (disabled) return;
		checked = !checked;
		onchange?.(checked);
	}

	function onKeydown(e: KeyboardEvent) {
		if (e.key === ' ' || e.key === 'Enter') {
			e.preventDefault();
			toggle();
		}
	}

	const trackBase =
		'relative inline-flex shrink-0 cursor-pointer items-center rounded-full transition-colors duration-200 ease-out focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50';
	const trackSize = $derived(size === 'sm' ? 'h-5 w-9' : 'h-6 w-11');
	const knobSize = $derived(size === 'sm' ? 'h-4 w-4' : 'h-5 w-5');
	const knobTranslate = $derived(
		size === 'sm'
			? checked
				? 'translate-x-4'
				: 'translate-x-0.5'
			: checked
				? 'translate-x-[1.375rem]'
				: 'translate-x-0.5'
	);
</script>

<button
	type="button"
	role="switch"
	aria-checked={checked}
	aria-label={ariaLabel ?? label}
	aria-labelledby={ariaLabelledby}
	{id}
	{disabled}
	onclick={toggle}
	onkeydown={onKeydown}
	class={cn(
		trackBase,
		trackSize,
		checked ? 'bg-primary shadow-[inset_0_1px_2px_rgba(0,0,0,0.18)]' : 'bg-muted-foreground/35',
		className
	)}
>
	<span
		aria-hidden="true"
		class={cn(
			'pointer-events-none inline-block transform rounded-full bg-white shadow-[0_2px_4px_rgba(80,50,20,0.35),0_1px_2px_rgba(80,50,20,0.18)] ring-0 transition-transform duration-200 ease-[cubic-bezier(0.34,1.56,0.64,1)]',
			knobSize,
			knobTranslate
		)}
	></span>
	{#if name !== undefined}
		<input type="hidden" {name} value={checked ? 'on' : ''} />
	{/if}
</button>
