<script>
    import { useDictionaryForm } from "$lib/components/composable/use-dictionary-form.svelte";
    import FormPageContainer from "$lib/components/reusable/form/form-page-container.svelte";
    import DictionaryFormRenderer from "$lib/components/reusable/form/dictionary-form-renderer.svelte";
    import { toast } from "svelte-sonner";
    import ReusableAlertDialog from "$lib/components/reusable/reusable-alert-dialog.svelte";
    import { useForm } from "$lib/components/composable/use-form.svelte";
    import { testMapDetailSchema, testMapDetailInitialForm, testMapDetailDefaultErrors, testMapDetailFormFields, buildTestMapPayload } from "$lib/components/dictionary/testmap/config/testmap-form-config";
    import { Separator } from "$lib/components/ui/separator/index.js";
    import PencilIcon from "@lucide/svelte/icons/pencil";
    import Trash2Icon from "@lucide/svelte/icons/trash-2";
    import * as Table from '$lib/components/ui/table/index.js';
    import { Button } from "$lib/components/ui/button/index.js";
    import { untrack } from "svelte";
    import { API } from "$lib/config/api";
    import { getChangedFields } from "$lib/utils/getChangedFields";
    import { onMount } from "svelte";
    import * as Tooltip from "$lib/components/ui/tooltip/index.js";

    let props = $props();

    const { masterDetail, formFields, formActions, schema, initialForm } = props.context;

    const { formState } = masterDetail;

    let editingId = $state(null);
    let idCounter = $state(0);
    let tempMap = $state([]);
    let deletedDetailIds = $state([]);
    let showDeleteConfirm = $state(false);
    let selectedRow = $state({});

    const testMapDetailFormState = useForm({
        schema: testMapDetailSchema,
        initialForm: testMapDetailInitialForm,
        defaultErrors: testMapDetailDefaultErrors,
    });

    const helpers = useDictionaryForm(formState);

    let showConfirm = $state(false);

    function snapshotForm() {
        return untrack(() => {
            const f = testMapDetailFormState.form;
            return {
                HostTestCode: f.HostTestCode ?? "",
                HostTestName: f.HostTestName ?? "",
                ClientTestCode: f.ClientTestCode ?? "",
                ClientTestName: f.ClientTestName ?? "",
                ConDefID: f.ConDefID ?? "",
            };
        });
    }

    function resetTestMapDetailForm() {
        testMapDetailFormState.reset();
        editingId = null;
    }

    function handleInsertDetail() {
        const row = {
            id: ++idCounter,
            TestMapDetailID: null,
            ...snapshotForm()
        };

        tempMap = [...tempMap, row];

        resetTestMapDetailForm();
    }

    async function handleEditDetail(row) {
        editingId = row.id;

        untrack(() => {
            const f = testMapDetailFormState.form;

            f.HostTestCode   = row.HostTestCode;
            f.HostTestName   = row.HostTestName;
            f.ClientTestCode = row.ClientTestCode;
            f.ClientTestName = row.ClientTestName;
            f.ConDefID       = row.ConDefID;
        });
    }

    function handleUpdateDetail() {
        const updated = snapshotForm();

        tempMap = tempMap.map((row) =>
            row.id === editingId ? {
                    ...row,
                    ...updated,
                    TestMapDetailID: row.TestMapDetailID ?? null
                } : row
        );
        resetTestMapDetailForm();
    }

    function handleCancelEditDetail() {
        resetTestMapDetailForm();
    }

    function handleRemoveDetail(id) {
        const row = tempMap.find(r => r.id === id);
        if (row?.TestMapDetailID) {
            deletedDetailIds.push(row.TestMapDetailID);
        }
        tempMap = tempMap.filter((row) => row.id !== id);
        if (editingId === id) {
            resetTestMapDetailForm();
        }
    }

    $effect(() => {
        const fields = mapFormFieldsTransformed;
        untrack(() => {
            fields.forEach(group => {
                group.rows.forEach(row => {
                    row.columns.forEach(col => {
                        if (col.type === 'select' && col.optionsEndpoint) {
                            formState.fetchOptions(col, formState.form);
                        }
                    });
                });
            });
        });
    });

    $effect(() => {
        const fields = mapDetailFormFieldsTransformed;

        untrack(() => {
            fields.forEach(group => {
                group.rows.forEach(row => {
                    row.columns.forEach(col => {
                        if (col.type === 'select' && col.optionsEndpoint) {
                            testMapDetailFormState.fetchOptions(col, testMapDetailFormState.form);
                        }
                    });
                });
            });
        });
    });

    function diffDetails(currentRows, originalRows) {
        const originalMap = new Map(
            originalRows
                .filter(item => item.TestMapDetailID)
                .map(item => [item.TestMapDetailID, item])
        );

        const updated = [];
        const detailKeys = ['HostTestCode', 'HostTestName', 'ClientTestCode', 'ClientTestName', 'ConDefID'];

        for (const item of currentRows) {
            if (!item.TestMapDetailID) continue;

            const orig = originalMap.get(item.TestMapDetailID);
            if (!orig) continue;

            const changed = detailKeys.some(
                key => item[key] !== orig[key]
            );

            if (changed) updated.push(item);
        }

        return updated;
    }
    
    async function handleEdit() {
        const currentPayload = buildTestMapPayload({
            mainForm: formState.form, 
            tempMap
        });
        const originalPayload = buildTestMapPayload({
            mainForm: masterDetail.formSnapshot, 
            tempMap: masterDetail.formSnapshot.details ?? []
        });

        const originalRows = masterDetail.formSnapshot.details ?? [];
        const updatedDetails = diffDetails(tempMap, originalRows);

        const changedFields = getChangedFields(originalPayload, currentPayload);
        const hasMainChanges = Object.keys(changedFields).length > 0;
        const hasDetailChanges = updatedDetails.length > 0 || tempMap.some(r => !r.TestMapDetailID) || deletedDetailIds.length > 0;
        
        if (!hasMainChanges && !hasDetailChanges) {
            toast('No changes detected');
            return;
        }

        const finalPayload = {
            TestMapID: formState.form.TestMapID,
            ...changedFields,
            ...(hasDetailChanges && {
                details: {
                    created: tempMap.filter(r => !r.TestMapDetailID),
                    edited: updatedDetails,
                    deleted: deletedDetailIds
                }
            })
        };

        console.log(finalPayload);  

        const result = await formState.save(masterDetail.mode, finalPayload);
        
        if (result.status === 'success') {
            console.log('Test Map updated successfully');
            toast('Test Map Updated!');
            masterDetail.exitForm(true);
        } else {
            console.error('Failed to update test map:', result.message);
            const errorMessages = result.messages ? Object.values(result.messages).join('\n') : 'Failed to update test map';
            toast.error(errorMessages)
        }
    }

    const primaryAction = $derived({
        label: 'Save',
        onClick: handleEdit,
        disabled: helpers.hasErrors || formState.isSaving.current,
        loading: formState.isSaving.current
    });

    const secondaryActions = [];

    const mapFormFieldsTransformed = $derived.by(() => {
        return formFields.map((group) => ({
            ...group,
            rows: group.rows.map((row) => ({
                ...row,
                columns: row.columns.map((col) => {
                    if (col.key === 'HostID') {
                        if (formState.form.HostType === 'HIS') {
                            return {
                                ...col,
                                type: 'select',
                                optionsEndpoint: `${API.BASE_URL}${API.HOSTAPP}`,
                                valueKey: 'HostAppID',
                                labelKey: 'HostAppName'
                            }
                        } else if (formState.form.HostType === 'SITE') {
                            return {
                                ...col,
                                type: 'select',
                                optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
                                valueKey: 'SiteID',
                                labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`
                            };
                        } else if (formState.form.HostType === 'WST') {
                            return {
                                ...col,
                                type: 'select',
                                optionsEndpoint: `${API.BASE_URL}${API.WORKSTATION}`,
                                valueKey: 'WorkstationID',
                                labelKey: 'WorkstationName'
                            };
                        } else if (formState.form.HostType === 'INST') {
                            return {
                                ...col,
                                type: 'select',
                                optionsEndpoint: `${API.BASE_URL}${API.EQUIPMENT}`,
                                valueKey: 'EID',
                                labelKey: 'InstrumentName'
                            }
                        }
                        return { ...col, type: 'text', optionsEndpoint: undefined };
                    }

                    if (col.key === 'ClientID') {
                        if (formState.form.ClientType === 'HIS') {
                            return {
                                ...col,
                                type: 'select',
                                optionsEndpoint: `${API.BASE_URL}${API.HOSTAPP}`,
                                valueKey: 'HostAppID',
                                labelKey: 'HostAppName'
                            }
                        } else if (formState.form.ClientType === 'SITE') {
                            return {
                                ...col,
                                type: 'select',
                                optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
                                valueKey: 'SiteID',
                                labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`
                            };
                        } else if (formState.form.ClientType === 'WST') {
                            return {
                                ...col,
                                type: 'select',
                                optionsEndpoint: `${API.BASE_URL}${API.WORKSTATION}`,
                                valueKey: 'WorkstationID',
                                labelKey: 'WorkstationName'
                            };
                        } else if (formState.form.ClientType === 'INST') {
                            return {
                                ...col,
                                type: 'select',
                                optionsEndpoint: `${API.BASE_URL}${API.EQUIPMENT}`,
                                valueKey: 'EID',
                                labelKey: 'InstrumentName'
                            }
                        }
                        return { ...col, type: 'text', optionsEndpoint: undefined };
                    }

					return col;
                })
            }))
        }));
    });

    const mapDetailFormFieldsTransformed = $derived.by(() => {
        return testMapDetailFormFields.map((group) => ({
            ...group,
            rows: group.rows.map((row) => ({
                ...row,
                columns: row.columns.map((col) => {
                    if (col.key === 'HostTestCode') {
                        if (formState.form.HostType === 'SITE' && formState.form.HostID) {
                            return {
                                ...col,
                                type: 'select',
                                optionsEndpoint: `${API.BASE_URL}${API.TEST}?SiteID=${formState.form.HostID}`,
                                valueKey: 'TestSiteCode',
                                labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`
                            };
                        }
                        return { ...col, type: 'text', optionsEndpoint: undefined };
                    }
 
                    if (col.key === 'ClientTestCode') {
                        if (formState.form.ClientType === 'SITE' && formState.form.ClientID) {
                            return {
                                ...col,
                                type: 'select',
                                optionsEndpoint: `${API.BASE_URL}${API.TEST}?SiteID=${formState.form.ClientID}`,
                                valueKey: 'TestSiteCode',
                                labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`
                            };
                        }
                        return { ...col, type: 'text', optionsEndpoint: undefined };
                    }

                    return col
                })
            }))
        }))
    })

    $effect(() => {
        const mainForm = formState.form;
        if (mainForm.details && Array.isArray(mainForm.details)) {
            tempMap = mainForm.details.map((row, index) => ({
                id: row.id ?? index + 1,
                ...row,
            }));
        }
    })

    $effect(() => {
		const maxId = tempMap.reduce((max, row) => {
			const rowId = typeof row.id === 'number' ? row.id : 0;
			return rowId > max ? rowId : max;
		}, 0);
		
		if (maxId > idCounter) {
			idCounter = maxId;
		}
	});

    function getLabel(fieldKey, value) {
		const opts = testMapDetailFormState.selectOptions[fieldKey] ?? [];
		const found = opts.find((o) => o.value == value);
		return found ? found.rawItem.ConName : value;
	}

    onMount(() => {
        masterDetail.registerExtraState({
            key: 'tempMap',
            get: () => tempMap,
            reset: () => { tempMap = []; idCounter = 0; editingId = null; },
        });
    });
</script>

<FormPageContainer title="Edit Test Map" {primaryAction} {secondaryActions}>
    <DictionaryFormRenderer
        {formState}
        formFields={mapFormFieldsTransformed}
        mode="edit"
    />
    <DictionaryFormRenderer 
        formState={testMapDetailFormState}
        formFields={mapDetailFormFieldsTransformed}
        mode="create"
    />
    <div class="flex flex-col gap-4">
        <div class="flex gap-2 mt-1 ms-2">
            {#if editingId !== null}
                <Button size="sm" class="cursor-pointer" onclick={handleUpdateDetail}>
                    Update
                </Button>
                <Button size="sm" variant="outline" class="cursor-pointer" onclick={handleCancelEditDetail}>
                    Cancel
                </Button>
            {:else}
                <Button size="sm" class="cursor-pointer" onclick={handleInsertDetail}
                disabled={Object.values(testMapDetailFormState.errors).some(v => v !== null)}>
                    Insert
                </Button>
            {/if}
        </div>
        
        <div>
            <Separator />
            <Table.Root>
                <Table.Header>
                    <Table.Row class="hover:bg-transparent">
                        <Table.Head>Host Test Code</Table.Head>
                        <Table.Head>Host Test Name</Table.Head>
                        <Table.Head>Client Test Code</Table.Head>
                        <Table.Head>Client Test Name</Table.Head>
                        <Table.Head>Container</Table.Head>
                        <Table.Head class="w-[80px]"></Table.Head>
                    </Table.Row>
                </Table.Header>
                <Table.Body>
                    {#if tempMap.length === 0}
                        <Table.Row>
                            <Table.Cell colspan={9} class="text-center text-muted-foreground py-6">
                                No data. Fill the form above and click Insert.
                            </Table.Cell>
                        </Table.Row>
                    {:else}
                        {#each tempMap as row (row.id)}
                            <Table.Row 
                                class="cursor-pointer hover:bg-muted/50"
                            >
                                <Table.Cell>{row.HostTestCode}</Table.Cell>
                                <Table.Cell>{row.HostTestName}</Table.Cell>
                                <Table.Cell>{row.ClientTestCode}</Table.Cell>
                                <Table.Cell>{row.ClientTestName}</Table.Cell>
                                <Table.Cell>{row.ConDefID ? getLabel('ConDefID', row.ConDefID) : '-'}</Table.Cell>
                                <Table.Cell>
                                    <div class="flex gap-1">
                                        <Tooltip.Provider>
                                            <Tooltip.Root>
                                                <Tooltip.Trigger>
                                                    <Button
                                                        size="icon"
                                                        variant="outline"
                                                        class="h-7 w-7 cursor-pointer"
                                                        onclick={() => handleEditDetail(row)}
                                                    >
                                                        <PencilIcon class="h-3.5 w-3.5" />
                                                    </Button>
                                                </Tooltip.Trigger>
                                                <Tooltip.Content>
                                                    <p>Edit</p>
                                                </Tooltip.Content>
                                            </Tooltip.Root>
                                        </Tooltip.Provider>
                                        <Tooltip.Provider>
                                            <Tooltip.Root>
                                                <Tooltip.Trigger>
                                                    <Button
                                                        size="icon"
                                                        variant="outline"
                                                        class="h-7 w-7 cursor-pointer"
                                                        onclick={() => {
                                                            selectedRow = row; 
                                                            showDeleteConfirm = true; 
                                                        }}
                                                    >
                                                        <Trash2Icon class="h-3.5 w-3.5" />
                                                    </Button>
                                                </Tooltip.Trigger>
                                                <Tooltip.Content>
                                                    <p>Delete</p>
                                                </Tooltip.Content>
                                            </Tooltip.Root>
                                        </Tooltip.Provider>
                                    </div>
                                </Table.Cell>
                            </Table.Row>
                        {/each}
                    {/if}
                </Table.Body>
            </Table.Root>
        </div>
    </div>
</FormPageContainer>

<ReusableAlertDialog
    bind:open={masterDetail.showExitConfirm}
    onConfirm={masterDetail.confirmExit}
/>

<ReusableAlertDialog
    bind:open={showDeleteConfirm}
    title="Delete Test Code?"
    description="Are you sure you want to disable this test code ({selectedRow.HostTestCode})?"
    confirmText="Delete"
    onConfirm={() => {
        handleRemoveDetail(selectedRow.id);
    }}
/>