<script>
    import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
    import * as Select from "$lib/components/ui/select/index.js";
    import { Toggle } from "$lib/components/ui/toggle/index.js";
    import { Button } from "$lib/components/ui/button/index.js";
    import { Input } from "$lib/components/ui/input/index.js";
    import { Label } from "$lib/components/ui/label/index.js";
    import { Spinner } from "$lib/components/ui/spinner/index.js";
    import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
    import { Badge } from "$lib/components/ui/badge/index.js";
    import * as InputGroup from "$lib/components/ui/input-group/index.js";
    import ChevronDownIcon from "@lucide/svelte/icons/chevron-down";
    import { Textarea } from "$lib/components/ui/textarea/index.js";

    let {
        formState,
        formFields,
        mode = 'create',
        disabledResultTypes = [],
        disabledReferenceTypes = [], 
        disabledSign = false,
        joinFields = $bindable(),
        hiddenFields,
        handleTestTypeChange,
        handleResultTypeChange,
        handleRefTypeChange,
    } = $props();

    let searchQuery = $state({});
    let dropdownOpen = $state({});

    function getFilteredOptions(key) {
        const query = searchQuery[key] || "";
        if (!query) return formState.selectOptions?.[key] ?? [];
        
        return (formState.selectOptions?.[key] ?? []).filter(opt => 
            opt.label.toLowerCase().includes(query.toLowerCase())
        );
    }

    $effect(() => {
        initializeDefaultValues();
    });
    
    async function initializeDefaultValues() {
        for (const group of formFields) {
            for (const row of group.rows) {
                for (const col of row.columns) {
                    if (col.type === "group") {
                        for (const child of col.columns) {
                            await handleDefaultValue(child);
                        }
                    } else {
                        await handleDefaultValue(col);
                    }
                }
            }
        }
    }
    
    async function handleDefaultValue(field) {
        if (!field.defaultValue || !field.optionsEndpoint) return;
        
        await formState.fetchOptions(field, formState.form);
        
        if (!formState.form[field.key]) {
            formState.form[field.key] = field.defaultValue;
        }
    }

    // function hasExactKeyword(input, keyword) {
    //     const regex = new RegExp(`\\b${keyword}\\b`, 'i');
    //     return regex.test(input);
    // }
</script>

{#snippet Fieldset({ key, label, required, type, optionsEndpoint, options, validateOn, dependsOn, endpointParamKey, valueKey, labelKey, txtKey })}
    <div class="flex w-full flex-col gap-1.5">
        <div class="flex justify-between items-center w-full">
            <Label>{label}</Label>
            {#if required}
                <span class="text-destructive text-xl leading-none h-3.5">*</span>
            {/if}
            <!-- {#if required || dynamicRequiredFields.includes(key)}
                <span class="text-destructive text-xl leading-none h-3.5">*</span>
            {/if} -->
        </div>

        <div class="relative flex flex-col items-center w-full">
            {#if type === "text"}
                <Input 
                    type="text" 
                    bind:value={formState.form[key]}
                    oninput={() => {
                        if (validateOn?.includes("input")) {
                            formState.validateField(key, formState.form[key], false);
                        }
                    }}
                    onblur={() => {
                        if (validateOn?.includes("blur")) {
                            validateFieldAsync(key, mode, originalData?.[key]);
                        }
                    }}
                    readonly={key === "NumRefType" || key === "TxtRefType" || key === "Level"}
                />
            {:else if type === "email"}
                <Input 
                    type="email" 
                    bind:value={formState.form[key]}
                    oninput={() => {
                        if (validateOn?.includes("input")) {
                            formState.validateField(key, formState.form[key], false);
                        }
                    }}
                    onblur={() => {
                        if (validateOn?.includes("blur")) {
                            formState.validateField(key, formState.form[key], false);
                        }
                    }}
                />
            {:else if type === "number"}
                <Input 
                    type="number" 
                    bind:value={formState.form[key]}
                    oninput={() => {
                        if (validateOn?.includes("input")) {
                            formState.validateField(key, formState.form[key], false);
                        }
                    }}
                    onblur={() => {
                        if (validateOn?.includes("blur")) {
                            formState.validateField(key, formState.form[key], false);
                        }
                    }}
                    onkeydown={(e) => ['e', 'E', '+', '-'].includes(e.key) && e.preventDefault()}
                />
            {:else if type === "textarea"}
                <Textarea 
                    class="flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
                    oninput={() => {
                        if (validateOn?.includes("input")) {
                            formState.validateField(key, formState.form[key], false);
                        }
                    }}
                    onblur={() => {
                        if (validateOn?.includes("blur")) {
                            formState.validateField(key, formState.form[key], false);
                        }
                    }}
                    bind:value={formState.form[key]}
                />
            {:else if type === "select"}
                {@const selectedLabel = formState.selectOptions?.[key]?.find(opt => opt.value === formState.form[key])?.label || "Choose"}
                {@const filteredOptions = getFilteredOptions(key)}
                <Select.Root type="single" bind:value={formState.form[key]} 
                    onValueChange={(val) => {
                        formState.form[key] = val;
                        if (validateOn?.includes("input")) {
                            formState.validateField?.(key, formState.form[key], false);
                        }
                        if (key === "TestType") {
                            handleTestTypeChange(val);
                        }
                        if (key === "Province") {
                            formState.form.City = "";
                            if (formState.selectOptions) {
                                formState.selectOptions.City = [];
                            }
                            if (formState.lastFetched) {
                                formState.lastFetched.City = null;
                            }
                        }
                        if (key === "ResultType") {
                            handleResultTypeChange(val);
                        }
                        if (key === "RefType") {
                            handleRefTypeChange(val);
                        }
                    }}
                    onOpenChange={(open) => {
                        if (open && optionsEndpoint) {
                            formState.fetchOptions?.(
                                { key, optionsEndpoint, dependsOn, endpointParamKey, valueKey, labelKey }, 
                                formState.form
                            );
                        }
                    }}
                >
                    <Select.Trigger class="w-full truncate">
                        {selectedLabel}
                    </Select.Trigger>
                    <Select.Content>
                        <div class="p-2">
                            <input
                                type="text"
                                placeholder="Search..."
                                class="w-full border rounded px-2 py-1 text-sm"
                                bind:value={searchQuery[key]}
                            />
                        </div>
                        {#if formState.loadingOptions?.[key]}
                            <Select.Item disabled value="loading">Loading...</Select.Item>
                        {:else}
                            {#if !required}
                                <Select.Item value="">- None -</Select.Item>
                            {/if}
                            {#each filteredOptions as option}
                                <Select.Item value={option.value}
                                disabled={key === "ResultType" && disabledResultTypes.includes(option.value) ||
                                        key === "RefType" && disabledReferenceTypes.includes(option.value)}
                                >
                                    {option.label}
                                </Select.Item>
                            {/each}
                        {/if}
                    </Select.Content>
                </Select.Root>
            <!-- {:else if type === "selectmultiple"}
                {@const filteredOptions = getFilteredOptions(key)}
                {@const selectedValues = Array.isArray(formState.form[key]) ? formState.form[key] : []}
                {@const selectedOptions = selectedValues
                    .map(val => formState.selectOptions?.[key]?.find(opt => opt.value === val))
                    .filter(Boolean)}
                
                <Select.Root type="multiple" bind:value={formState.form[key]}
                    onValueChange={(vals) => {
                        formState.form[key] = vals;
                        if (validateOn?.includes("input")) {
                            formState.validateField?.(key, formState.form[key], false);
                        }
                        if (key === 'FormulaInput') {
                            formState.validateField?.('FormulaCode', formState.form['FormulaCode'], false);
                        }
                    }}
                    onOpenChange={(open) => {
                        if (open && optionsEndpoint) {
                            formState.fetchOptions?.(
                                { key, optionsEndpoint, dependsOn, endpointParamKey, valueKey, labelKey }, 
                                formState.form
                            );
                        }
                    }}
                >
                    <Select.Trigger class="w-full min-h-[42px]">
                        {#if selectedOptions.length === 0}
                            <span class="text-muted-foreground">Choose</span>
                        {:else}
                            <div class="flex flex-wrap gap-1">
                                {#each selectedOptions as option}
                                    <Badge variant="secondary" class="text-xs">
                                        {option.label}
                                    </Badge>
                                {/each}
                            </div>
                        {/if}
                    </Select.Trigger>
                    <Select.Content>
                        <div class="p-2">
                            <input
                                type="text"
                                placeholder="Search..."
                                class="w-full border rounded px-2 py-1 text-sm"
                                bind:value={searchQuery[key]}
                            />
                        </div>
                        {#if formState.loadingOptions?.[key]}
                            <Select.Item disabled value="loading">Loading...</Select.Item>
                        {:else}
                            {#if !required}
                                <Select.Item value="">- None -</Select.Item>
                            {/if}
                            {#each filteredOptions as option}
                                <Select.Item value={option.value}
                                disabled={key === "ResultType" && disabledResultTypes.includes(option.value) ||
                                        key === "RefType" && disabledReferenceTypes.includes(option.value)}
                                >
                                    {option.label}
                                </Select.Item>
                            {/each}
                        {/if}
                    </Select.Content>
                    {#if selectedValues.length > 0}
                        <button
                            class="w-full px-2 py-1.5 text-left text-sm hover:bg-accent hover:text-accent-foreground"
                            onclick={() => formState.form[key] = []}
                        >
                            Unselect All
                        </button>
                    {/if}
                </Select.Root> -->
            {:else if type === "date"}
                <ReusableCalendar 
                    bind:value={formState.form[key]}
                    parentFunction={(dateStr) => {
                        formState.form[key] = dateStr;
                        if (validateOn?.includes("input")) {
                            formState.validateField(key, dateStr, false);
                        }
                    }}
                />
            {:else if type === "signvalue"}                 
                <InputGroup.Root>
                    <InputGroup.Input 
                        placeholder="Type here" 
                        bind:value={formState.form[txtKey]}
                    />
                    <InputGroup.Addon align="inline-start">
                        <DropdownMenu.Root
                            onOpenChange={(open) => {
                                dropdownOpen[key] = open;
                                if (open && optionsEndpoint) {
                                    formState.fetchOptions?.(
                                        { key, optionsEndpoint, valueKey, labelKey }, 
                                        formState.form
                                    );
                                }
                            }}
                        >
                            <DropdownMenu.Trigger>
                                {#snippet child({ props })}
                                    <InputGroup.Button
                                        {...props}
                                        variant="ghost" disabled={disabledSign}
                                    >
                                        {formState.selectOptions?.[key]?.find(
                                            opt => opt.value === formState.form[key]
                                        )?.label || 'Choose'}
                                        <ChevronDownIcon  />
                                    </InputGroup.Button>
                                {/snippet}
                            </DropdownMenu.Trigger>
                            <DropdownMenu.Content align="start">
                                {#if formState.loadingOptions?.[key]}
                                    <DropdownMenu.Item disabled>
                                        Loading...
                                    </DropdownMenu.Item>
                                {:else}
                                    {#each formState.selectOptions?.[key] || [] as option}
                                        <DropdownMenu.Item
                                            onclick={() => {
                                                formState.form[key] = option.value;
                                                dropdownOpen[key] = false;
                                            }}
                                        >
                                            {option.label}
                                        </DropdownMenu.Item>
                                    {/each}
                                {/if}
                            </DropdownMenu.Content>
                        </DropdownMenu.Root>
                    </InputGroup.Addon>
                </InputGroup.Root>
            {:else if type === "agejoin"}
                <div class="flex items-center gap-2 w-full">
                    <InputGroup.Root>
                        <InputGroup.Input type="number" bind:value={joinFields[key].YY}/>
                        <InputGroup.Addon align="inline-end">
                            <InputGroup.Text>Year</InputGroup.Text>
                        </InputGroup.Addon>
                    </InputGroup.Root>
                    <InputGroup.Root>
                        <InputGroup.Input type="number" bind:value={joinFields[key].MM}/>
                        <InputGroup.Addon align="inline-end">
                            <InputGroup.Text>Month</InputGroup.Text>
                        </InputGroup.Addon>
                    </InputGroup.Root>
                    <InputGroup.Root>
                        <InputGroup.Input type="number" bind:value={joinFields[key].DD}/>
                        <InputGroup.Addon align="inline-end">
                            <InputGroup.Text>Day</InputGroup.Text>
                        </InputGroup.Addon>
                    </InputGroup.Root>
                </div>
            {:else}
                <Input 
                    type="text" 
                    bind:value={formState.form[key]}
                    placeholder="Custom field type: {type}"
                />
            {/if}
            <div
                class={`absolute min-h-[1rem] w-full ${
                    key === 'FormulaCode' ? 'top-20' : 'top-8'
                }`}
            >
                <!-- {#if formState.errors[key] || dynamicRequiredFields.includes(key)}
                    <span class="text-destructive text-sm leading-none">
                        {formState.errors[key]}
                    </span>
                {/if} -->
                {#if formState.errors[key]}
                    <span class="text-destructive text-sm leading-none">
                        {formState.errors[key]}
                    </span>
                <!-- {:else if dynamicRequiredFields.includes(key)}
                    <span class="text-destructive text-sm leading-none">
                        Required
                    </span> -->
                {/if}
            </div>
        </div>
    </div>
{/snippet}

<div class="p-2 space-y-6">
    {#each formFields as group}
        <div class="space-y-6">
            {#if group.title}
                <div class="text-md 2xl:text-lg font-semibold italic">
                    <span class="border-b-2 border-primary">{group.title}</span>
                </div>
            {/if}

            {#each group.rows as row}
                {@const visibleColumns = row.columns.filter(col => !hiddenFields?.includes(col.key))}

                {#if visibleColumns.length > 0}
                    <div
                        class="grid grid-cols-1 space-y-2 gap-6 md:gap-4"
                        class:md:grid-cols-1={visibleColumns.length === 1 && visibleColumns[0].fullWidth !== false}
                        class:md:grid-cols-2={visibleColumns.length === 2 || (visibleColumns.length === 1 && visibleColumns[0].fullWidth === false)}
                        class:md:grid-cols-3={visibleColumns.length === 3}
                    >
                        {#each visibleColumns as col}
                            {#if col.type === "group"}
                                {@const visibleChildColumns = col.columns.filter(child => !hiddenFields?.includes(child.key))}
                                
                                {#if visibleChildColumns.length > 0}
                                    <div
                                        class="grid grid-cols-1 gap-6 md:gap-2"
                                        class:md:grid-cols-1={visibleChildColumns.length === 1 && visibleChildColumns[0].fullWidth !== false}
                                        class:md:grid-cols-2={visibleChildColumns.length === 2 || (visibleChildColumns.length === 1 && visibleChildColumns[0].fullWidth === false)}
                                        class:md:grid-cols-3={visibleChildColumns.length === 3}
                                    >
                                        {#each visibleChildColumns as child}
                                            {@render Fieldset(child)}
                                        {/each}
                                    </div>
                                {/if}
                            {:else}
                                {@render Fieldset(col)}
                            {/if}
                        {/each}
                    </div>
                {/if}
            {/each}
        </div>
    {/each}
</div>

<!-- <div class="p-2 space-y-6">
    {#each formFields as group}
        <div class="space-y-6">
            {#if group.title}
                <div class="text-md 2xl:text-lg font-semibold italic">
                    <span class="border-b-2 border-primary">{group.title}</span>
                </div>
            {/if}

            {#each group.rows as row}
                <div
                    class="grid grid-cols-1 space-y-2 gap-6 md:gap-4"
                    class:md:grid-cols-1={row.columns.length === 1 && row.columns[0].fullWidth !== false}
                    class:md:grid-cols-2={row.columns.length === 2 || (row.columns.length === 1 && row.columns[0].fullWidth === false)}
                    class:md:grid-cols-3={row.columns.length === 3}
                >
                    {#each row.columns as col}
                        {#if col.type === "group"}
                            <div
                                class="grid grid-cols-1 gap-6 md:gap-2"
                                class:md:grid-cols-1={col.columns.length === 1 && col.columns[0].fullWidth !== false}
                                class:md:grid-cols-2={col.columns.length === 2 || (col.columns.length === 1 && col.columns[0].fullWidth === false)}
                                class:md:grid-cols-3={col.columns.length === 3}
                            >
                                {#each col.columns as child}
                                    {@render Fieldset(child)}
                                {/each}
                            </div>
                        {:else}
                            {@render Fieldset(col)}
                        {/if}
                    {/each}
                </div>
            {/each}
        </div>
    {/each}
</div> -->