<!--
    Component: Input
    design-system input. Zero border-radius, Space Grotesk, precise states.
-->
<script lang="ts">
import { cn } from '$shared/lib';
import XIcon from '@lucide/svelte/icons/x';
import type { Snippet } from 'svelte';
import { cubicOut } from 'svelte/easing';
import type { HTMLInputAttributes } from 'svelte/elements';
import { scale } from 'svelte/transition';
import {
    inputSizeConfig,
    inputVariantConfig,
} from './config';
import type {
    InputSize,
    InputVariant,
} from './types';

interface Props extends Omit<HTMLInputAttributes, 'size'> {
    /**
     * Visual style variant
     * @default 'default'
     */
    variant?: InputVariant;
    /**
     * Input size
     * @default 'md'
     */
    size?: InputSize;
    /**
     * Invalid state
     */
    error?: boolean;
    /**
     * Helper text
     */
    helperText?: string;
    /**
     * Show clear button
     * @default false
     */
    showClearButton?: boolean;
    /**
     * Clear button callback
     */
    onclear?: () => void;
    /**
     * Left icon snippet
     */
    leftIcon?: Snippet<[InputSize]>;
    /**
     * Right icon snippet
     */
    rightIcon?: Snippet<[InputSize]>;
    /**
     * Full width
     * @default false
     */
    fullWidth?: boolean;
    /**
     * Input value
     */
    value?: string | number | readonly string[];
    /**
     * CSS classes
     */
    class?: string;
}

let {
    variant = 'default',
    size = 'md',
    error = false,
    helperText,
    showClearButton = false,
    onclear,
    leftIcon,
    rightIcon,
    fullWidth = false,
    value = $bindable(''),
    class: className,
    ...rest
}: Props = $props();

const hasValue = $derived(value !== undefined && value !== '');
const showClear = $derived(showClearButton && hasValue && !!onclear);
const hasRightSlot = $derived(!!rightIcon || showClearButton);
const cfg = $derived(inputSizeConfig[size]);
const styles = $derived(inputVariantConfig[variant]);

const inputClasses = $derived(cn(
    'font-primary rounded-none outline-none transition-all duration-200',
    'text-neutral-900 dark:text-neutral-100',
    'placeholder:text-neutral-400 dark:placeholder:text-neutral-600',
    'disabled:opacity-50 disabled:cursor-not-allowed',
    cfg.input,
    cfg.text,
    cfg.height,
    styles.base,
    error ? styles.error : styles.focus,
    !!leftIcon && 'pl-10',
    hasRightSlot && 'pr-10',
    fullWidth && 'w-full',
    className,
));
</script>

<div class={cn('flex flex-col gap-1', fullWidth && 'w-full')}>
    <div class={cn('relative group', fullWidth && 'w-full')}>
        <!-- Left icon slot -->
        {#if leftIcon}
            <div class="absolute left-3 top-1/2 -translate-y-1/2 text-neutral-400 dark:text-neutral-600 pointer-events-none z-10 flex items-center">
                {@render leftIcon(size)}
            </div>
        {/if}

        <!-- Input -->
        <input class={inputClasses} bind:value {...rest} />

        <!-- Right slot: clear button + rightIcon -->
        {#if hasRightSlot}
            <div class="absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-2 z-10">
                {#if showClear}
                    <button
                        type="button"
                        tabindex={-1}
                        onclick={onclear}
                        class="text-neutral-400 hover:text-brand transition-colors p-0.5 flex items-center"
                        in:scale={{ duration: 150, start: 0.8, easing: cubicOut }}
                        out:scale={{ duration: 100, start: 0.8, easing: cubicOut }}
                    >
                        <XIcon size={cfg.clearIcon} />
                    </button>
                {/if}

                {#if rightIcon}
                    <div class="text-neutral-400 dark:text-neutral-600 flex items-center">
                        {@render rightIcon(size)}
                    </div>
                {/if}
            </div>
        {/if}
    </div>

    <!-- Helper / error text -->
    {#if helperText}
        <span
            class={cn(
                'text-2xs font-mono tracking-wide px-1',
                error ? 'text-brand ' : 'text-secondary',
            )}
        >
            {helperText}
        </span>
    {/if}
</div>
