<!--
    Component: ComboControl
    Provides the same functionality as the original ComboControl but lacks increase/decrease buttons.
-->
<script lang="ts">
import type { TypographyControl } from '$shared/lib';
import { Button } from '$shared/shadcn/ui/button';
import { Root as ButtonGroupRoot } from '$shared/shadcn/ui/button-group';
import {
    Content as PopoverContent,
    Root as PopoverRoot,
    Trigger as PopoverTrigger,
} from '$shared/shadcn/ui/popover';
import {
    Content as TooltipContent,
    Root as TooltipRoot,
    Trigger as TooltipTrigger,
} from '$shared/shadcn/ui/tooltip';
import { cn } from '$shared/shadcn/utils/shadcn-utils';
import { Input } from '$shared/ui';
import { Slider } from '$shared/ui';
import MinusIcon from '@lucide/svelte/icons/minus';
import PlusIcon from '@lucide/svelte/icons/plus';
import {
    type Orientation,
    REGEXP_ONLY_DIGITS,
} from 'bits-ui';
import type { ChangeEventHandler } from 'svelte/elements';
import IconButton from '../IconButton/IconButton.svelte';

interface Props {
    /**
     * Control instance
     */
    control: TypographyControl;
    /**
     * Orientation
     */
    orientation?: Orientation;
    /**
     * Label text
     */
    label?: string;
    /**
     * CSS class
     */
    class?: string;
    /**
     * Show scale flag
     */
    showScale?: boolean;
    /**
     * Flag that change component appearance
     * from the one with increase/decrease buttons and popover with input + slider
     * to just input + slider
     */
    reduced?: boolean;
    /**
     * Text for increase button aria-label
     */
    increaseLabel?: string;
    /**
     * Text for decrease button aria-label
     */
    decreaseLabel?: string;
    /**
     * Text for control button aria-label
     */
    controlLabel?: string;
}

let {
    control,
    orientation = 'vertical',
    label,
    class: className,
    showScale = true,
    reduced = false,
    increaseLabel = 'Increase',
    decreaseLabel = 'Decrease',
    controlLabel,
}: Props = $props();

let inputValue = $state(String(control.value));

$effect(() => {
    inputValue = String(control.value);
});

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

function calculateScale(index: number): number | string {
    const calculate = () =>
        orientation === 'horizontal'
            ? (control.min + (index * (control.max - control.min) / 4))
            : (control.max - (index * (control.max - control.min) / 4));
    return Number.isInteger(control.step)
        ? Math.round(calculate())
        : (calculate()).toFixed(2);
}
</script>

{#snippet ComboControl()}
    <div
        class={cn(
            'flex gap-4 sm:p-4 rounded-xl transition-all duration-300',
            'backdrop-blur-md',
            orientation === 'horizontal' ? 'flex-row items-end w-full' : 'flex-col items-center h-full',
            className,
        )}
    >
        <div class={cn('relative', orientation === 'horizontal' ? 'w-full' : 'h-full')}>
            {#if showScale}
                <div
                    class={cn(
                        'absolute flex justify-between',
                        orientation === 'horizontal' ? 'flex-row w-full -top-5 px-0.5' : 'flex-col h-full -left-5 py-0.5',
                    )}
                >
                    {#each Array(5) as _, i}
                        <div
                            class={cn(
                                'flex items-center gap-1.5',
                                orientation === 'horizontal' ? 'flex-col' : 'flex-row',
                            )}
                        >
                            <span class="font-mono text-[0.375rem] text-gray-400 tabular-nums">
                                {calculateScale(i)}
                            </span>
                            <div class={cn('bg-gray-300', orientation === 'horizontal' ? 'w-px h-1' : 'h-px w-1')}>
                            </div>
                        </div>
                    {/each}
                </div>
            {/if}

            <Slider
                class={cn(orientation === 'horizontal' ? 'w-full' : 'h-full')}
                bind:value={control.value}
                min={control.min}
                max={control.max}
                step={control.step}
                {orientation}
            />
        </div>

        <Input
            class="h-10 rounded-lg w-12 pl-1 pr-1 sm:pr-1 md:pr-1 sm:pl-1 md:pl-1 text-center"
            value={inputValue}
            onchange={handleInputChange}
            min={control.min}
            max={control.max}
            step={control.step}
            pattern={REGEXP_ONLY_DIGITS}
            variant="ghost"
        />

        {#if label}
            <div class="flex items-center gap-2 opacity-70">
                <div class="w-1 h-1 rounded-full bg-gray-900"></div>
                <div class="w-px h-2 bg-gray-400/50"></div>
                <span class="font-mono text-[8px] uppercase tracking-[0.2em] text-gray-500 font-medium">
                    {label}
                </span>
            </div>
        {/if}
    </div>
{/snippet}

{#if reduced}
    {@render ComboControl()}
{:else}
    <TooltipRoot>
        <ButtonGroupRoot class="bg-transparent border-none shadow-none">
            <TooltipTrigger class="flex items-center">
                <IconButton
                    onclick={control.decrease}
                    disabled={control.isAtMin}
                    aria-label={decreaseLabel}
                    rotation="counterclockwise"
                >
                    {#snippet icon({ className })}
                        <MinusIcon class={className} />
                    {/snippet}
                </IconButton>
                <PopoverRoot>
                    <PopoverTrigger>
                        {#snippet child({ props })}
                            <Button
                                {...props}
                                variant="ghost"
                                class="hover:bg-white/50 hover:font-bold bg-white/20 border-none duration-150 will-change-transform active:scale-95 cursor-pointer"
                                size="icon"
                                aria-label={controlLabel}
                            >
                                {control.value}
                            </Button>
                        {/snippet}
                    </PopoverTrigger>
                    <PopoverContent class="w-auto h-64 sm:px-1 py-0">
                        {@render ComboControl()}
                    </PopoverContent>
                </PopoverRoot>

                <IconButton
                    aria-label={increaseLabel}
                    onclick={control.increase}
                    disabled={control.isAtMax}
                    rotation="clockwise"
                >
                    {#snippet icon({ className })}
                        <PlusIcon class={className} />
                    {/snippet}
                </IconButton>
            </TooltipTrigger>
        </ButtonGroupRoot>
        {#if controlLabel}
            <TooltipContent>
                {controlLabel}
            </TooltipContent>
        {/if}
    </TooltipRoot>
{/if}
