<script lang="ts">
import { Button } from '$shared/shadcn/ui/button';
import * as ButtonGroup from '$shared/shadcn/ui/button-group';
import { Input } from '$shared/shadcn/ui/input';
import * as Popover from '$shared/shadcn/ui/popover';
import { Slider } from '$shared/shadcn/ui/slider';
import MinusIcon from '@lucide/svelte/icons/minus';
import PlusIcon from '@lucide/svelte/icons/plus';
import type { ChangeEventHandler } from 'svelte/elements';

interface ComboControlProps {
    /**
     * Controlled value
     */
    value: number;
    /**
     * Callback function to handle value change
     */
    onChange: (value: number) => void;
    /**
     * Callback function to handle increase
     */
    onIncrease: () => void;
    /**
     * Callback function to handle decrease
     */
    onDecrease: () => void;
    /**
     * Text for increase button aria-label
     */
    increaseLabel?: string;
    /**
     * Text for decrease button aria-label
     */
    decreaseLabel?: string;
    /**
     * Flag for disabling increase button
     */
    increaseDisabled?: boolean;
    /**
     * Flag for disabling decrease button
     */
    decreaseDisabled?: boolean;
    /**
     * Text for control button aria-label
     */
    controlLabel?: string;
    /**
     * Minimum value for the input
     */
    minValue?: number;
    /**
     * Maximum value for the input
     */
    maxValue?: number;
    /**
     * Step value for the slider
     */
    step?: number;
}

const {
    value,
    onChange,
    onIncrease,
    onDecrease,
    increaseLabel,
    decreaseLabel,
    increaseDisabled,
    decreaseDisabled,
    controlLabel,
    minValue = 0,
    maxValue = 100,
    step = 1,
}: ComboControlProps = $props();

// Local state for the slider to prevent infinite loops
let sliderValue = $state(value);

// Sync sliderValue when external value changes
$effect(() => {
    sliderValue = value;
});

const handleInputChange: ChangeEventHandler<HTMLInputElement> = event => {
    const parsedValue = parseFloat(event.currentTarget.value);
    if (!isNaN(parsedValue)) {
        onChange(parsedValue);
    }
};

/**
 * Handle slider value change.
 * The Slider component passes the value as a number directly.
 */
const handleSliderChange = (value: number) => {
    onChange(value);
};
</script>

<ButtonGroup.Root>
    <Button
        variant="outline"
        size="icon"
        aria-label={decreaseLabel}
        onclick={onDecrease}
        disabled={decreaseDisabled}
    >
        <MinusIcon />
    </Button>
    <Popover.Root>
        <Popover.Trigger>
            {#snippet child({ props })}
                <Button
                    {...props}
                    variant="outline"
                    size="icon"
                    aria-label={controlLabel}
                >
                    {value}
                </Button>
            {/snippet}
        </Popover.Trigger>
        <Popover.Content class="w-auto p-4">
            <div class="flex flex-col items-center gap-3">
                <Slider
                    min={minValue}
                    max={maxValue}
                    step={step}
                    value={sliderValue}
                    onValueChange={handleSliderChange}
                    type="single"
                    orientation="vertical"
                    class="h-48"
                />
                <Input
                    value={String(value)}
                    min={minValue}
                    max={maxValue}
                    onchange={handleInputChange}
                    class="w-16 text-center"
                />
            </div>
        </Popover.Content>
    </Popover.Root>
    <Button
        variant="outline"
        size="icon"
        aria-label={increaseLabel}
        onclick={onIncrease}
        disabled={increaseDisabled}
    >
        <PlusIcon />
    </Button>
</ButtonGroup.Root>
