<script>
    import { Button } from "$lib/components/ui/button/index.js";
    import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
    import { Input } from "$lib/components/ui/input/index.js";
    import { Label } from "$lib/components/ui/label/index.js";
    import ChevronUpIcon from "@lucide/svelte/icons/chevron-up";
    import { Spinner } from "$lib/components/ui/spinner/index.js";
    import * as Select from "$lib/components/ui/select/index.js";
    import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
    import ReusableCalendarTimepicker from "$lib/components/reusable/reusable-calendar-timepicker.svelte";
    import CustodianModal from "../modal/custodian-modal.svelte";
    import LinktoModal from "../modal/linkto-modal.svelte";
    import ReusableUpload from "$lib/components/reusable/reusable-upload.svelte";

    let {
        formState,
        formFields,
        uploadErrors,
        isChecking,
        linkToDisplay,
        validateIdentifier,
        validateFieldAsync,
        mode = 'create'
    } = $props();

    let searchQuery = $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() {
        console.log('object');
        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;
        
        // Fetch options
        await formState.fetchOptions(field, formState.form);
        
        // Set default jika form masih kosong
        if (!formState.form[field.key]) {
            formState.form[field.key] = field.defaultValue;
        }
    }
</script>

{#snippet Fieldset({ key, label, required, type, optionsEndpoint, options, validateOn, dependsOn, endpointParamKey })}
    <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}
        </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);
                        }
                    }}
                />
            {: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);
                        }
                    }}
                />
            {: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 === "datetime"}
                <ReusableCalendarTimepicker 
                    bind:value={formState.form[key]}
                    onValueChange={(val) => {
                        formState.form[key] = val;
                        if (validateOn?.includes("input")) {
                            formState.validateField(key, formState.form[key], false);
                        }
                    }}
                />
            {: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]}
                ></textarea>
            {: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 === "Province") {
                            formState.form.City = "";
                            formState.selectOptions.City = [];
                            formState.lastFetched.City = null;
                        }
                    }}
                    onOpenChange={(open) => {
                        if (open && optionsEndpoint) {
                            formState.fetchOptions(
                                { key, optionsEndpoint, dependsOn, endpointParamKey }, 
                                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}>
                                    {option.label}
                                </Select.Item>
                            {/each}
                        {/if}
                    </Select.Content>
                </Select.Root>
            {:else if type === "identity"}
                {@const selectedLabel = formState.selectOptions[key]?.find(opt => opt.value === formState.form.PatIdt.IdentifierType)?.label || "Choose"}
                <div class="flex items-center w-full">
                    <Select.Root type="single" bind:value={formState.form.PatIdt.IdentifierType} 
                        onOpenChange={(open) => {
                            if (open && optionsEndpoint) {
                                formState.fetchOptions({ key, optionsEndpoint});
                            }
                        }} 
                        onValueChange={(val) => {
                            formState.form.PatIdt = {
                            IdentifierType: val,
                            Identifier:''
                            };
                        }}
                    >
                        <Select.Trigger class="w-full truncate text-muted-foreground rounded-r-none">
                            {selectedLabel}
                        </Select.Trigger>
                        <Select.Content>
                            {#if formState.loadingOptions[key]}
                                <Select.Item disabled value="loading">Loading...</Select.Item>
                            {:else}
                                {#if !required}
                                    <Select.Item value="">- None -</Select.Item>
                                {/if}
                                {#each formState.selectOptions[key] ?? [] as option}
                                    <Select.Item value={option.value}>
                                        {option.label}
                                    </Select.Item>
                                {/each}
                            {/if}
                        </Select.Content>
                    </Select.Root>
                    <Input type="text" class="rounded-l-none" disabled={!formState.form.PatIdt.IdentifierType} bind:value={formState.form.PatIdt.Identifier} oninput={validateIdentifier} />
                </div>
            {:else if type === "custodian"}
                <div class="flex items-center w-full">
                    <Input type="text" class="rounded-r-none" readonly bind:value={formState.form[key].PatientID} />
                    <CustodianModal {formState} mode="new"/>
                </div>
            {:else if type === "linkto"}
                <div class="flex items-center w-full">
                    <Input 
                        type="text" 
                        class="rounded-r-none" 
                        readonly 
                        value={linkToDisplay}
                        placeholder="No linked patients"
                    />
                    <LinktoModal {formState} />
                </div>
            {:else if type === "fileupload"}
                <div class="flex flex-col w-full">
                    <ReusableUpload attachments={formState.form[key]} errors={uploadErrors}/>
                    {#if Object.keys(uploadErrors).length > 0}
                        <div class="flex flex-col justify-start text-destructive">
                            {#each Object.entries(uploadErrors) as [file, msg]}
                                <span>{msg}</span>
                            {/each}
                        </div>
                    {/if}
                </div>
            {:else}
                <Input 
                    type="text" 
                    bind:value={formState.form[key]}
                    placeholder="Custom field type: {type}"
                />
            {/if}

            <div class="absolute top-8 min-h-[1rem] w-full">
                {#if isChecking[key]}
                    <div class="flex items-center gap-1 mt-1">
                        <Spinner />
                        <span class="text-sm text-muted-foreground">Checking...</span>
                    </div>
                {:else if formState.errors[key]}
                    <span class="text-destructive text-sm leading-none">
                        {formState.errors[key]}
                    </span>
                {/if}
            </div>
        </div>
    </div>
{/snippet}

<div class="flex-1 min-h-0 overflow-y-auto 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}
                    class:md:grid-cols-2={row.columns.length === 2}
                    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}
                                class:md:grid-cols-2={col.columns.length === 2}
                                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>